关于Arrays类中asList(T... a)泛型参数辨析

前提

我们需要知道两点

(1)T指的是泛型类型,它只能是引用类型,何为引用类型?在java中除了基本数据类型(如byte、short、int、long、float、double、boolean、char)之外的所有类型都是引用类型。引用类型包括类(class)、接口(interface)、数组(array)等

 (2)我们asList返回值是一个List<T>类型,也就是说我们传递什么T最后返回的List中元素类型就是什么T类型,比如我们传递一个Integer 那么List中元素就是Integer,我们传递一个int [] 那么我们list中元素就是int[],有的同志就要问了,为什么传递过去的事int [] 泛型T不会识别为int ,刚才我们说了泛型只能是引用类型,但是我们int是基本类型,不会识别为引用类型,所以我们参数接收的时候直接就将int [] 识别成了引用类型,所以我们返回的结果List<int[]>就是这种类型的。

实验

  public static void main(String[] args) {

        int[] a = {2,3,4,5};
        Integer[] b = {2,3,4,5};

        List listA = Arrays.asList(a);
        List listA1 = Arrays.asList(2,3,4,5);
        List listB = Arrays.asList(b);

        System.out.println(listA.size());
        System.out.println(listA1.size());
        System.out.println(listB.size());
      
         System.out.println("ListA元素类型:"+listA.get(0).getClass());
                                        
        System.out.println("ListA元素:"+Arrays.toString((int[]) listA.get(0)));

        System.out.println("ListA1元素类型:"+listA1.get(0).getClass());

        System.out.println("ListB元素类型:"+listB.get(0).getClass());
    }
 

 运行结果

我们可以看到我们传递过去的int [] array数组,接受参数确实将int [] 识别为了T,也就是说我们List中元素是int[] ,所以我们的元素个数是1。

对于我们传递过去的Arrays.asList(2,3,4,5);这个可变参数我们没有指定类型,但是java会自动装箱操作,将这个几个参数自动封装为Integer类型。

补充

上面都是一维数组,那么如果是二维数组又是什么情况呢?

我们以Arrays中的toArray方法为例

public Object[] toArray() {

return Arrays.copyOf(elementData, size);

}

@SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // 新建一个运行时类型的数组,但是ArrayList数组的内容
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
            //调用System提供的arraycopy()方法实现数组之间的复制
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people,(a,b)->{
            if(a[0]==b[0]) return a[1]-b[1];
            return b[0]-a[0];
        });
         LinkedList<int[]> que = new LinkedList<>();
         for (int[] p : people) {
             que.add(p[1],p);
         }
         return que.toArray(new int[people.length][]);
    }
}

实际上我们传递过去的二维数组int[][] ,我们参数中泛型T识别的是int[] ,然后传递到源码中的a实际上就是我们int[] 类型的一维数组,这个可以这样理解:int[3][2] 实际上是 int[3] {int[2], int[2], int[2]}。

然后返回值直接就是T[] 就是int[3][]。

下面这个例子更加好理解一些。

List<int[]> res = new ArrayList<>();
res.add(new int[]{100});
int[][] a = res.toArray(new int[0][]);
System.out.println(a[0][0]);

//成功运行并输出
100

其他问题

2.asList()方法返回对象使用add()方法抛出异常
先进行如下测试:

  public static void main(String[] args) {
        List<String> pets = Arrays.asList("tiger","mice");
        pets.add("lion");
    }
 

结果如下:

我们这里可以看到他抛出了一个异常,难道add方法不是List的基本用法吗?我们继续扒一下源码。

原来原来Arrays的asList方法使用的ArrayList类是一个内部定义的类,而不是java.util.ArrayList类。其部分源码如下:

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        @java.io.Serial
        private static final long serialVersionUID = -2764017481108945198L;
        @SuppressWarnings("serial") // Conditionally serializable
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }
        
        ....
     }

我们可以看到这是一个静态内部类,存储数组元素的a变量是final类型的,由此判断,这个静态内部类是不能做任何内部元素的添加删除操作的!就跟String类一样,String对象存储字符数组的变量也是有final修饰符的。因为一旦增加数组元素,这个数组容量已经定好的容器就无法装载增加的元素了。

内部类里面并没有add,remove方法,我们可以看下这个类继承的AbstractList类里面对这些方法的实现:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {  
    ........  
  
    public void add(int index, E element) {  
        throw new UnsupportedOperationException();  
    }  
  
    public E remove(int index) {  
        throw new UnsupportedOperationException();  
    }  

找到异常的来源了,我们使用asList得到的对象add、remove方法直接就是抛出异常。那么我们如果要想对asList得到的对象使用add、remove方法,该怎么办呢?

List<String> pets = new ArrayList<String>(Arrays.asList("a", "b", "c")); 

可以将传入的参数转换为一个ArrayList对象返回。

3.通过Arrays.asList方法将数组转成集合后,使用set方法修改元素,为什么原来的数组的值也会改变?
测试:

public static void main(String[] args){
            String[] strings={"A","B","C"};
            List<String> stringList=Arrays.asList(strings);
            stringList.set(0,"G");
            System.out.println(stringList);
            System.out.println(strings[0]);
        }
 

结果:

​我们可以看到集合的值和原数组的第一个值都被修改了,为什么原数组也会被修改呢?

原因是静态内部类ArrayList的成员变量a使用了final,用于存储集合的数组引用始终被强制指向原有数组。

所以原数组也会被修改。

​那么怎么在不修改原数组的基础上修改集合呢?我们同样可以采取将传入的参数转换为一个ArrayList对象返回的方式。
参考链接:https://blog.csdn.net/qq_51634677/article/details/131223655

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/407942.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Flutter/Android】运行到安卓手机上一直卡在 Running Gradle task ‘assembleDebug‘... 的终极解决办法

方法步骤简要 查看你的Flutter项目需要什么版本的 Gradle 插件&#xff1a; 下载这个插件&#xff1a; 方法一&#xff1a;浏览器输入&#xff1a;https://services.gradle.org/distributions/gradle-7.6.3-all.zip 方法二&#xff1a;去Gradle官网找对应的版本&#xff1a;h…

Uniapp小程序开发-底部tabbar的开发思路

文章目录 前言一、uniapp 实现 tabbar二、图标使用网络图片后端返回tabbar信息uniapp方式中的setTabBarItem 总结 前言 记录uniapp 开发小程序的底部tabbar &#xff0c;这里讨论的不是自定义tabbar的情况。而是使用wx.setTabBarItem(Object object) 这个api的情况。关于custo…

IT廉连看——C语言——分支语句

IT廉连看—分支语句 一、什么是语句 C语句可分为以下五类&#xff1a; 表达式语句 函数调用语句 控制语句 复合语句 空语句 本周后面介绍的是控制语句。 控制语句用于控制程序的执行流程&#xff0c;以实现程序的各种结构方式&#xff0c;它们由特定的语句定义符组成&…

OT 安全解决方案:探索技术

IT 和 OT 安全的融合&#xff1a;更好的防御方法 OT 安全解决方案下一个时代&#xff1a; 为了应对不断升级的威胁形势&#xff0c;组织认识到迫切需要采用统一的信息技术 (IT) 和运营技术 (OT) 安全方法。IT 和 OT 安全的融合代表了一种范式转变&#xff0c;承认这些传统孤立领…

了解 JavaScript 中的重放攻击和复现攻击

在网络安全领域&#xff0c;重放攻击&#xff08;Replay Attack&#xff09;和复现攻击&#xff08;Playback Attack&#xff09;是一些可能导致安全漏洞的攻击形式。这两种攻击类型涉及在通信过程中再次发送已经捕获的数据&#xff0c;以达到欺骗系统的目的。本文将介绍 JavaS…

vue3 实现 el-pagination页面分页组件的封装以及调用

示例图 一、组件代码 <template><el-config-provider :locale"zhCn"><el-pagination background class"lj-paging" layout"prev, pager, next, jumper" :pager-count"5" :total"total":current-page"p…

leetcode单调栈

739. 每日温度 请根据每日 气温 列表&#xff0c;重新生成一个列表。对应位置的输出为&#xff1a;要想观测到更高的气温&#xff0c;至少需要等待的天数。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 例如&#xff0c;给定一个列表 temperatures [73, …

计算机组成原理(14)----总线

目录 一.总线的物理实现 二.总线概述 三.总线的特性 四.总线的分类 &#xff08;1&#xff09;按数据传输格式分类 •串行总线 •并行总线 &#xff08;2&#xff09;按总线功能分类 •片内总线 •系统总线 系统总线的结构 •通信总线 &#xff08;3&#xff09;按…

激光雷达反光板算法总结

1 高反特征提取 首先,从雷达原始数据,提取到高反点;根据雷达的规格书提供的不同材料的强度,设定合适的阈值;;更优的方法是根据距离设定不同的阈值 2 反光板及反光柱的聚类 根据高反点是否连续进行聚类,同时结合距离及雷达的角度分辨率,计算出针对不同尺寸的反光板或反…

Redis 有哪些架构模式?讲讲各自的特点

单机版模式 特点&#xff1a;简单 问题&#xff1a; 1、内存容量有限 2、处理能力有限 3、无法高可用。 主从复制 Redis 的复制&#xff08;replication&#xff09;功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品&#xff0c;其中被复制的服务器为主服…

STL容器之list

​ 1.封装除了对数据的保护、更好地管理数据之外&#xff0c;还有实现了对上层的统一&#xff1b; ​ 2.类模板参数的不同&#xff0c;一方面是为了实例化出来不同的类&#xff0c;另一方面是为了实现类的成员函数的不同&#xff1b; 一、认识list ​ 1.list是一种带头双向循…

[嵌入式系统-34]:RT-Thread -19- 新手指南:RT-Thread标准版系统架构

目录 一、RT-Thread 简介 二、RT-Thread 概述 三、许可协议 四、RT-Thread 的架构 4.1 内核层&#xff1a; 4.2 组件与服务层&#xff1a; 4.3 RT-Thread 软件包&#xff1a; 一、RT-Thread 简介 作为一名 RTOS 的初学者&#xff0c;也许你对 RT-Thread 还比较陌生。然…

*MYSQL--索引--内部原理

MYSQL的索引根据功能,主要有三大类型: 1.HASH索引 2.二叉树 3.BTREE索引 一:HASH索引 1.内部原理: 在设置了某列为索引列之后,并且开始或者将要在相应索引列创建数据的时候,系统通过某种算法 F(X) 自动计算出来一个十六进制的哈希值,这个哈希值能够对应相应的字段值 所以…

2.openEuler概述及安装指南(二)

openEuler OECA认证辅导,标红的文字为学习重点和考点。 如果需要做实验,建议下载麒麟信安、银河麒麟、统信等具有图形化的操作系统,其安装与openeuler基本一致。 1.安装过程及配置 使用光盘引导安装: 此处以光盘安装为例介绍安装openEuler,其他安装方式除在启动安装时的…

我的NPI项目之设备系统启动(八) -- Android14的GKI2.0开发步骤和注意事项

GKI是什么&#xff1f; Google为什么要推行GKI&#xff1f; GKI全称General Kernel Image。GKI在framework和kernel之间提供了标准接口&#xff0c;使得android OS能够轻松适配/维护/兼容不同的设备和linux kernel。 Google引入GKI的目的是将Framework和Kernel进一步的解耦。因…

virtualenv env_name 使用 virtualenv 创建 python 虚拟环境

为什么要用这个 win7 32 环境下 pycharm 只能用低版本的&#xff0c;比如 2016,2018 此时pycharm 图形界面创建的 虚拟环境版本很低&#xff0c;有些包不兼容&#xff0c;因此用 virtualenv 模块&#xff0c;可以创建 20 版本以上的虚拟环境 virtualenv env_name官方文档 http…

java_URL中的URL编码转换成中文

问题描述 上传文件后&#xff0c;获得的URL中包含了URL编码&#xff0c;导致在前端展示文件名时出现乱码 最终效果 解决思路&#xff1a; 1、先按照英文逗号切割URL 2、截取字符串中URL编码部分(含后缀名) 3、使用正则匹配截取到的字符串中的URL编码 4、转换URL编码为中文&a…

React18源码: Fiber树中的全局状态与双缓冲

Fiber树构造 在React运行时中&#xff0c;fiber树构造位于 react-reconciler 包在正式解读 fiber 树构造之前&#xff0c;再次回顾一下renconciler的4个阶段 1.输入阶段&#xff1a;衔接react-dom包&#xff0c;承接fiber更新请求2.注册调度任务&#xff1a;与调度中心(schedu…

HarmonyOS创建一个ArkTS卡片

创建一个ArkTS卡片 在已有的应用工程中&#xff0c;创建ArkTS卡片&#xff0c;具体操作方式如下。 创建卡片。 根据实际业务场景&#xff0c;选择一个卡片模板。 在选择卡片的开发语言类型&#xff08;Language&#xff09;时&#xff0c;选择ArkTS选项&#xff0c;然后单…

QT Widget自定义菜单

此文以设置QListWidget的自定义菜单为例&#xff0c;其他继承于QWidget的类也都可以按类似的方法去实现。 1、ui文件设置contextMenuPolicy属性为CustomContextMenu 2、添加槽函数 /*** brief onCustomContextMenuRequested 右键弹出菜单* param pos 右键的坐标*/void onCusto…