####关于Arrays.asList(T)这个API

久未见 提交于 2019-11-28 20:29:23

####关于Arrays.asList(T)这个API

参考: https://docs.oracle.com/javase/tutorial/java/generics/why.html https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

所以会研究这个问题,是因为在写代码的时候遇到了这个,很反直觉. 同样都是{120,130}竟然返回了不同的类型.

    public static void main(String[] args) {
        Integer[] pangs = {120, 130};
        int[] fats = {120, 130};
        List<Integer> pangList = Arrays.asList(pangs);
        List<int[]> fatsList = Arrays.asList(fats);
    }

Auto boxing is the automatic conversion that the Java compiler makes, between the primitive types and their corresponding object wrapper classes.

Generic Types A generic type is a generic class or interface that is parameterized over types.

以下是对返回类型推断的一些解释(军功章的一半分给石五花), 首先明确两点

  1. auto boxing unboxing是对基本数据类型及其包装类型来说的.
  2. generic type 是对class或者interface来说的.

然后看传入Arrays.asList(fats)的fats的类型是int[] 注意int[]并不是基本数据类型, 基本数据类型是一回事而,基本数据类型的数组又是另外一回事. 所以这里并没有想当然的auto boxing发生.

接着就是vargs, ...通常在编译时会转变成对应的一维数组 对应这里的上下文即int[][] 数据类型为int[]的一维数组 所以返回的类型就是List<int[]>


编译时类型是List,但是运行时的类型是java.util.Arrays.ArrayList.

String[] str = {"hello","world"}
List<String> listStr = Arrays.asList(str);
//这里就要抛异常了
listStr.add("shit")
  * Returns a fixed-size list backed by the specified array.  (Changes to
     * the returned list "write through" to the array.)  This method acts
     * as bridge between array-based and collection-based APIs, in
     * combination with {@link Collection#toArray}.  The returned list is
     * serializable and implements {@link RandomAccess}.
     * @param <T> the class of the objects in the array
     * @param a the array by which the list will be backed
     * @return a list view of the specified array
     */
    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

重点就是这两句: Returns a fixed-size list backed by the specified array. return a list view of the specified array.

This method acts as bridge between array-based and collection-based APIs. 把原先基于数组的改成基于collection的,方便你可能会调用一些collection相关的API.

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

这个代码命名很鸡贼,就叫的ArrayList. 注意这里的ArrayList可不是那个常用的--->java.util.ArrayList. 它是---->java.util.Arrays.ArrayList. 然后看它代码的实现.声明长这个样子

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable{
          ...
        }

java.util.AbstractList这个类的声明

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {}
public abstract class AbstractCollection<E> implements Collection<E> 

这是java.util.List这个类的声明

public interface List<E> extends Collection<E> { ... }        

这就是为啥你在外面可以用List来接,你懂我意思.

Exception in thread "main" java.lang.UnsupportedOperationException 至于那个异常,是java.util.AbstractList抛出的,它压根就没有实现. 你的java.util.ArrayList可以这么干是因为它自己实现了.

这是AbstractList类的add方法

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

####问题来了,为什么Java要把它设计成fixed-size的呢?

  • 因为这个API的作用仅仅acts as bridge between array-based and collection-based APIs
  • 数组本来就不可以变啊,你懂我意思吧,不要抬杠. 我说不可变的意思你懂吧,但是数组里的元素是可以变化的. 起码数组的大小什么的是不可以变的.嗯 数组本来就是fixed-size的. 事实上java.util.Arrays.ArrayList里是提供了相应的API比如set,get什么的.
       public E get(int index) {
            return a[index];
       }

        @Override
        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }

只要不动大小怎么着都可以. 如果你改变数组的大小了,就不是原来那个数组了.

可是如果就是想要一个不fixed-size的List的话,可以这么着

int[] fats = {120,130};
new ArrayList(Arrays.asList(fats));

这把返回的就是常用的java.util.ArrayList了.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!