• Java中数组转集合总结


    一、使用Arrays.asList() 方法

    package com.joshua317;
    
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) {
            String[] namesArr = {"joshua317","joshua318","joshua319"};
            List<String> namesLst = Arrays.asList(namesArr);
            for (String name: namesLst) {
                System.out.println(name);
            }
        }
    }
    
     对于Arrays.asList()方法需要注意以下几点: 1.该方法返回的是基于数组的List视图(List view)。所以,这种方式是将数组转换为List的最快的方式。因为返回的只是视图,不需要多余的内存来创建新的List以及复制操作。

    2.该方法返回的List是长度是固定的(fixed),不是只读的。所以我们不能进行删除、添加操作,而可以使用set()方法进行修改元素操作。如果你对返回的List执行add()添加新元素,会返回UnsupportedOperationException。

    package com.joshua317;
    
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) {
            String[] namesArr = {"joshua317","joshua318","joshua319"};
            List<String> namesLst = Arrays.asList(namesArr);
            namesLst.add("joshua319");
            for (String name: namesLst) {
                System.out.println(name);
            }
        }
    }
    
    3.因为该方法返回的是基于原数组的List视图,所以,当我们使用set方法修改了List中的元素的时候,那么原来的数组也会跟着改变(这是视图的特性)。
    package com.joshua317;
    
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) {
            String[] namesArr = {"joshua317","joshua318","joshua319"};
            List<String> namesLst = Arrays.asList(namesArr);
            namesLst.set(0,"joshua320");
            System.out.println("==========list==========");
            for (String name: namesLst) {
                System.out.println(name);
            }
            System.out.println("==========array==========");
            for (String name: namesArr) {
                System.out.println(name);
            }
        }
    }
    4.从java 5开始,该方法支持泛型,所以我们可以从数组中得到类型安全ArrayList。

    注意:

    1.如果我们想让转换为只读的List,可以使用Collections.unmodifiableList()方法来将数组转换为指定List。

    package com.joshua317;
    
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) {
            String[] namesArr = {"joshua317","joshua318","joshua319"};
            final List<String> namesLst = Collections.unmodifiableList(Arrays.asList(namesArr));
    
            for (String name: namesLst) {
                System.out.println(name);
            }
        }
    }
    
    2.如果想返回的方法能够进行添加、删除元素操作,则可以使用new ArrayList(Arrays.asList(array)) ,这样就会创建一个对象类型的ArrayList,并将数组的内容拷贝过去。
    package com.joshua317;
    
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) {
            String[] namesArr = {"joshua317","joshua318","joshua319"};
            ArrayList<String> namesLst = new ArrayList<>(Arrays.asList(namesArr));
            namesLst.add("joshua320");
    
            for (String name: namesLst) {
                System.out.println(name);
            }
        }
    }

    二、使用Collections.addAll()方法

    使用Collections.addAll()方法没有第一种方法高效,但是更加灵活。同样也是新建一个ArrayList,将数组的内容复制进去。

    package com.joshua317;
    
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) {
            String[] namesArr = {"joshua317","joshua318","joshua319"};
            ArrayList<String> namesLst = new ArrayList<>();
    
            Collections.addAll(namesLst, namesArr);
            namesLst.add("joshua320");
    
            for (String name: namesLst) {
                System.out.println(name);
            }
        }
    }
     对于Collections.addAll()方法:

    1.没有Arrays.asList()快,但是更加灵活。

    2.该方法实际上是将数组的内容复制到ArrayList中

    3.因为是复制内容到ArrayList中,所以我们对ArrayList进行修改、添加、删除操作都不会影响原来的数组。

    4.该方法相当于一个添加操作。该方法并不会覆盖ArrayList中已经存在的元素。

    package com.joshua317;
    
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) {
            String[] namesArr = {"joshua317","joshua318","joshua319"};
            ArrayList<String> namesLst = new ArrayList<>();
    
            Collections.addAll(namesLst, namesArr);
            namesLst.add("---------");
            Collections.addAll(namesLst, namesArr);
    
            for (String name: namesLst) {
                System.out.println(name);
            }
        }
    }

    三、使用ArrayList的构造方法

    其实上面方法一中已经提到了,使用ArrayList的构造方法同时结合了Arrays.asList方法

    package com.joshua317;
    
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) {
            String[] namesArr = {"joshua317","joshua318","joshua319"};
            ArrayList<String> namesLst = new ArrayList<>(Arrays.asList(namesArr));
            namesLst.add("joshua320");
    
            for (String name: namesLst) {
                System.out.println(name);
            }
        }
    }
    
     
    ArrayList构造方法:

    ArrayList(Collection < ? extends E > c) : 构造一个包含特定容器的元素的列表,并且根据容器迭代器的顺序返回。 所以构造方法所做的事情如下:

    1.将容器c转换为一个数组

    2.将数组拷贝到ArrayList中称为”elementData”的数组中

    ArrayList的构造方法的源码如下:

      public ArrayList(Collection<? extends E> c) {
            Object[] a = c.toArray();
            if ((size = a.length) != 0) {
                if (c.getClass() == ArrayList.class) {
                    elementData = a;
                } else {
                    elementData = Arrays.copyOf(a, size, Object[].class);
                }
            } else {
                // replace with empty array.
                elementData = EMPTY_ELEMENTDATA;
            }
        }
    

    四、使用ArrayList的addAll()方法

    ArrayList的addAll()方法结合Arrays.asList方法使用

    package com.joshua317;
    
    import java.util.*;
    
    public class Main {
    
        public static void main(String[] args) {
            String[] namesArr = {"joshua317","joshua318","joshua319"};
            ArrayList<String> namesLst = new ArrayList<>();
    
            namesLst.addAll(Arrays.asList(namesArr));
            namesLst.add("joshua320");
    
            for (String name: namesLst) {
                System.out.println(name);
            }
        }
    }
     ArrayList.addAll(Collection < ? extends E > c) : 构造一个包含特定容器的元素的列表,并且根据容器迭代器的顺序返回。基本上和构造方法的原理一样。 所以addAll方法所做的事情如下:

    1.将容器c转换为一个数组

    2.将数组拷贝到ArrayList中称为”elementData”的数组中

    ArrayList的addAll方法的源码如下:

      public boolean addAll(Collection<? extends E> c) {
            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityInternal(size + numNew);  // Increments modCount
            System.arraycopy(a, 0, elementData, size, numNew);
            size += numNew;
            return numNew != 0;
        }
    

    五、拓展

    5.1 为何对Arrays.asList()返回的List进行添加、删除操作会报错,而set方法却可以使用?

    来看下Arrays.asList()方法相关源代码

     public static <T> List<T> asList(T... a) {
            return new ArrayList<>(a);
        }
        
    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")
            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;
            }
    
            @Override
            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;
            }
    
            @Override
            public int indexOf(Object o) {
                E[] a = this.a;
                if (o == null) {
                    for (int i = 0; i < a.length; i++)
                        if (a[i] == null)
                            return i;
                } else {
                    for (int i = 0; i < a.length; i++)
                        if (o.equals(a[i]))
                            return i;
                }
                return -1;
            }
    
            @Override
            public boolean contains(Object o) {
                return indexOf(o) != -1;
            }
    
            @Override
            public Spliterator<E> spliterator() {
                return Spliterators.spliterator(a, Spliterator.ORDERED);
            }
    
            @Override
            public void forEach(Consumer<? super E> action) {
                Objects.requireNonNull(action);
                for (E e : a) {
                    action.accept(e);
                }
            }
    
            @Override
            public void replaceAll(UnaryOperator<E> operator) {
                Objects.requireNonNull(operator);
                E[] a = this.a;
                for (int i = 0; i < a.length; i++) {
                    a[i] = operator.apply(a[i]);
                }
            }
    
            @Override
            public void sort(Comparator<? super E> c) {
                Arrays.sort(a, c);
            }
        }
        
    

    根据源码我们可以得知,Arrays.asList()方法返回的是个内部的ArrayList,这个类同样是AbstractList的一种实现。而该ArrayList就只有以下方法,并没有实现add和remove方法:

    contain(Object)
    get(int)
    indexOf(Object)
    set(int)
    size()
    toArray()
    toArray(T[])
    

    根本就没有add()和remove()方法。这个类由于是AbstractList的一种实现,AbstractList的add和remove方法会有异常抛出:

     /**
         * 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;
        }
    

    所以 当我们对返回的List执行add和remove方法时,就会报UnsupportedOperationException了。但是因为有set()方法,所以,我们可以修改返回的List。

    5.2 我们说Arrays.asList()返回的是基于原数组的List视图, 而且修改List的元素时候,原数组的内容也会同时改变,这又是为何呢?

    根据上面的代码,我们可以知道, 我们调用返回的ArrayList的set(),get(), indexOf(), contain(),size()这些方法,本质上都是去对原数组进行对应的操作。所以,我们改变返回的ArrayList中的内容的时候,原数组也会同时改变。这就是集合视图(collection view),集合了常用的方法。

    5.3 为何返回的ArrayList的长度是固定的?还有为什么Arrays.asList()方法最快?

    还是上面的代码,一般来说,ArrayList内部有一个对象类型数组作为实例变量来存放ArrayList中的数据。而上面的内部类中,ArrayList的这个实例变量就是a,而它只是将引用指向了原数组,并未将原数组的内容复制到a中。这样就没有进行复制操作,也没有创建新的数组对象,自然最快了。

    同时,该内部类ArrayList并为提供add方法等方法,自然是无法修改ArrayList的长度。而且因为是直接将实例变量a指向原数组,我们知道数组一旦初始化后就没法修改它的大小了,所以原数组不能改变大小,自然返回的ArrayList的长度也不能改变长度,长度就只能是固定的。

     

  • 相关阅读:
    CookieUtil.java
    观察者模式
    ELK日志分析系统
    Zookeeper安装配置及简单使用
    Zookeeper
    MBMD(MobileNet-based tracking by detection algorithm)作者答疑
    python代码迷之错误(ModuleNotFoundError: No module named 'caffe.proto')
    深度学习中易混概念小结
    Python爬虫小结
    VOT工具操作指南(踩过的坑)
  • 原文地址:https://www.cnblogs.com/joshua317/p/15885113.html
Copyright © 2020-2023  润新知