zoukankan      html  css  js  c++  java
  • Java数组转集合与集合转数组的坑

    Java中将数组转为集合,会用到Arrays.asList()的方法,然而,这个方法却与我们的预期期望存在一些出入,当用到asList方法将数组转化成List列表时,对得到的List列表进行add()和remove()操作, JVM会抛出异常:java.lang.UnsupportedOperationException异常 

    Arrays.asList返回的是同样的ArrayList,为什么就不能使用add和remove方法呢?

    接下来我们来看一下Arrays.asList 源码 

      public static <T> List<T> asList(T... a) {
            return new ArrayList<>(a);
        }
     /**
         * @serial include
         */
        private static class ArrayList<E> extends AbstractList<E>
            implements RandomAccess, java.io.Serializable
        {
            private static final long serialVersionUID = -2764017481108945198L;
            private final E[] a;
    
            ArrayList(E[] array) {
                a = Objects.requireNonNull(array);
            }
    
            @Override
            public int size() {
                return a.length;
            }
    
            @Override
            public Object[] toArray() {
                return a.clone();
            }
    
            @Override
            @SuppressWarnings("unchecked")

    AbstractList源码:

    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
        /**
         * Sole constructor.  (For invocation by subclass constructors, typically
         * implicit.)
         */
        protected AbstractList() {
        }
    
        /**
         * Appends the specified element to the end of this list (optional
         * operation).
         *
         * <p>Lists that support this operation may place limitations on what
         * elements may be added to this list.  In particular, some
         * lists will refuse to add null elements, and others will impose
         * restrictions on the type of elements that may be added.  List
         * classes should clearly specify in their documentation any restrictions
         * on what elements may be added.
         *
         * <p>This implementation calls {@code add(size(), e)}.
         *
         * <p>Note that this implementation throws an
         * {@code UnsupportedOperationException} unless
         * {@link #add(int, Object) add(int, E)} is overridden.
         *
         * @param e element to be appended to this list
         * @return {@code true} (as specified by {@link Collection#add})
         * @throws UnsupportedOperationException if the {@code add} operation
         *         is not supported by this list
         * @throws ClassCastException if the class of the specified element
         *         prevents it from being added to this list
         * @throws NullPointerException if the specified element is null and this
         *         list does not permit null elements
         * @throws IllegalArgumentException if some property of this element
         *         prevents it from being added to this list
         */
        public boolean add(E e) {
            add(size(), e);
            return true;
        }
    
        /**
         * {@inheritDoc}
         *
         * @throws IndexOutOfBoundsException {@inheritDoc}
         */
        abstract public E get(int index);
    
        /**
         * {@inheritDoc}
         *
         * <p>This implementation always throws an
         * {@code UnsupportedOperationException}.
         *
         * @throws UnsupportedOperationException {@inheritDoc}
         * @throws ClassCastException            {@inheritDoc}
         * @throws NullPointerException          {@inheritDoc}
         * @throws IllegalArgumentException      {@inheritDoc}
         * @throws IndexOutOfBoundsException     {@inheritDoc}
         */
        public E set(int index, E element) {
            throw new UnsupportedOperationException();
        }
    
        /**
         * {@inheritDoc}
         *
         * <p>This implementation always throws an
         * {@code UnsupportedOperationException}.
         *
         * @throws UnsupportedOperationException {@inheritDoc}
         * @throws ClassCastException            {@inheritDoc}
         * @throws NullPointerException          {@inheritDoc}
         * @throws IllegalArgumentException      {@inheritDoc}
         * @throws IndexOutOfBoundsException     {@inheritDoc}
         */
        public void add(int index, E element) {
            throw new UnsupportedOperationException();
        }
    
        /**
         * {@inheritDoc}
         *
         * <p>This implementation always throws an
         * {@code UnsupportedOperationException}.
         *
         * @throws UnsupportedOperationException {@inheritDoc}
         * @throws IndexOutOfBoundsException     {@inheritDoc}
         */
        public E remove(int index) {
            throw new UnsupportedOperationException();
        }

    由源码可见,UnsupportedOperationException 是AbstractList抛出的,因为Arrays中的ArrayList并没有实现remove()和add()方法,所以抛出了异常。 
    所以说 Arrays.asList 返回的 List 是一个不可变长度的列表,此列表不再具备原 List 的很多特性,因此慎用 Arrays.asList 方法。


    ArrayList中构造方法:

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

    看一段这样的代码: 

    import java.util.Arrays;
    import java.util.List;
    
    public class Test2{
        public static void main(String[] args) {
            int[] array = new int[]{1,2,3,4,5};
            List list = Arrays.asList(array);
            System.out.println(list.size());
        }
    }

    Arrays 的内部类 ArrayList 构造方法接收的是一个泛型数组,即数组类型不能为基本类型,应该为其对应的包装类型(传即入引用类型),否则传入的基本类型的整个数组,将被编译器视为一个引用参数,

    所以原始类型不能作为 Arrays.asList 方法的参数,否则会被当做一个参数


    再来看看在Java中将集合转为数组,ArrayList提供了一个将List转为数组的一个非常方便的方法toArray。toArray有两个重载的方法:

      @Override
            public Object[] toArray() {
                return a.clone();
            }
       @Override
            @SuppressWarnings("unchecked")
            public <T> T[] toArray(T[] a) {
                int size = size();
                if (a.length < size)
                    return Arrays.copyOf(this.a, size,
                                         (Class<? extends T[]>) a.getClass());
                System.arraycopy(this.a, 0, a, 0, size);
                if (a.length > size)
                    a[size] = null;
                return a;
            }

    对于第一个重载方法,是将list直接转为Object[] 数组;

    第二种方法是将list转化为你所需要类型的数组,当然我们用的时候会转化为与list内容相同的类型。

     若采用第一种toArray方法,是这样写:

    1 ArrayList<String> list=new ArrayList<String>();
    2         for (int i = 0; i < 10; i++) {
    3             list.add(""+i);
    4         }
    5          
    6         String[] array= (String[]) list.toArray();

    结果一运行,报错:

    Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;

    第一个方法不能将Object[] 转化为String[],我们需要修改为:

    1 Object[] arr = list.toArray();
    2         for (int i = 0; i < arr.length; i++) {
    3             String e = (String) arr[i];
    4             System.out.println(e);
    5         }

    建议用第二种方法:普通数组基本类型必须改为包装类

    import java.util.ArrayList;
    import java.util.List;
    
    public class Test2{
        public static void main(String[] args) {
            List<Integer> list = new ArrayList();
            list.add(1);
            list.add(2);
            list.add(3);
            Integer[] array = new Integer[list.size()];
            list.toArray(array);
            for (int i:array){
                System.out.print(i+" ");
            }
        }
    }

     或者

    set.toArray(new Integer[set.size()]);

    set好处是去除重复元素

  • 相关阅读:
    扫雷游戏:C++生成一个扫雷底板
    为《信息学奥赛一本通》平反(除了OJ很差和代码用宋体)
    关于最大公约数欧几里得算法辗转相除及最小公倍数算法拓展C++学习记录
    【Python】如何用较快速度用Python程序增加博客访问量——CSDN、博客园、知乎(应该包括简书)
    STL学习笔记之next_permutation函数
    C++集合容器STL结构Set
    11111111111
    express + mysql实践
    express实践
    ws:一个 Node.js WebSocket 库
  • 原文地址:https://www.cnblogs.com/hetaoyuan/p/11236999.html
Copyright © 2011-2022 走看看