资讯专栏INFORMATION COLUMN

数组和列表的转换问题

ChristmasBoy / 2978人阅读

摘要:以下指代数组,指代数组列表。常见的转换方法是或。在的使用过程中需要注意,当要转换的长度小于的时,不要试图通过传入形参的方式进行转换,虽然这在的长度大于时不会出现问题。所以,极度建议在转换之前初始化的长度为的,并且使用返回值重新给赋值。

Array 和 List 都是我们在开发过程中常见的数据结构。我们都知道 Array 是定长的,List 是可变长。而且,List 的实现类 ArrayList 也是根据 Array 去实现的。

以下 Array 指代数组,List 指代数组列表。
Array 转 List

当然最原始的方法就是使用遍历的方式,将 Array 中的元素都添加到 List 中。这种实现方式这里不作赘述。

Java1.2 之后,Jdk 语言提供 Arrays 这个工具类。大大简化了我们常见的 Array 操作,但是也有不少需要注意的问题。

如下:

Integer[] a = { 1, 2 };
List l = Arrays.asList(a);

这是我们常见的 Array 转换 List 的方式,但是这个使用上有一个问题。当对 List 对象 l 进行列表插入操作时:

l.add(3);

程序就会抛出异常 java.lang.UnsupportedOperationException。这是为什么呢?

查看 Arrays.asList 源码发现,

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

这里返回的 ArrayList 并不是 java.util.ArrayList 而是 java.util.Arrays.ArrayList。Arrays 又新建了一个 ArrayList 内部类,实现了一些基本 get set 方法。

回头查看 java.util.Arrays.ArrayList.ArrayList(E[] array) 构造函数,

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

不难发现,java.util.Arrays.ArrayList 虽然打着 List 的旗号,继承了 AbstractList 。但是其只是在 Array 的基础上进行了简单的封转,AbstractList 中则是直接重写了 add 方法,表示这个方法是不允许操作。

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

明白了这个错误产生的原因,回头想一下 Java 的这些开发者们为什么这样设计。

ArrayList 中如果要添加一个元素,则需要先对其内部的 Array 进行扩容,然后将 Old Array 复制到扩容后的 New Array 中。如果 Array 转 List 仅仅是读取操作,或是在 Array 的 Size 范围之内进行替换操作,再将 Array 复制一遍,不免会对内存进行浪费,倒不如直接将原始的 Array 直接拿来维护更为直接和高效(正如java.util.Arrays.ArrayList的实现方式)。

明白这个缘由之后,如果要在 Array 转 List 之后,不只有只读操作,那么则需要下面的实现,

List l = new ArrayList<>(Arrays.asList(a));

虽然在我们日常的开发过程中,已经习惯了使用 ArrayList 去代替 Array,但是了解此处 Java 的转换过程还是能够让我们少踩坑。

List 转 Array

因为 Array 的长度不可变,所以这个转换过程中,会有长度不匹配的情况。

常见的转换方法是 ArrayList.toArray()ArrayList.toArray(T[])

这两个实现的共同点是都是对 ArrayList 中的 Array 进行 Copy 操作,生成一个新的数组返回。不同点是前者返回值是 Object[],后者是 T[]

ArrayList.toArray(T[]) 的使用过程中需要注意,当要转换的 Array 长度小于 ArrayList 的 size 时,不要试图通过传入形参的方式进行转换,虽然这在 Array 的长度大于 List 时不会出现问题。

如下代码:

// l [1, 2, 3]
Integer[] a = new Integer[2];
l.toArray(a); // error 正确写法:a = l.toArray(a);
Stream.of(a).forEach(System.out::println);

输出结果是:null null

查看源码实现:

public  T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a"s runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

// Arrays.copyOf
public static  T[] copyOf(U[] original, int newLength, Class newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

可见,当 a.length < size 成立,入参 a 并没有被使用,所以 a 依然是 new Integer[2]

所以,极度建议在转换之前初始化 Array 的长度为 ArrayList 的 size,并且使用返回值重新给 Array 赋值。

// l [1, 2, 3]
Integer[] b = new Integer[l.size()];
l.toArray(b);
Stream.of(b).forEach(System.out::println);

原文地址:https://xdbin.com/blog/8a9eec5167da2d4501681e8c3f180001

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73103.html

相关文章

  • 翻译连载 | JavaScript轻量级函数式编程-第 8 章:列表操作 |《你不知道JS》姊妹篇

    摘要:通过对一系列任务建模来理解一些非常重要的函数式编程在列表操作中的价值一些些看起来不像列表的语句作为列表操作,而不是单独执行。映射我们将采用最基础和最简单的操作来开启函数式编程列表操作的探索。函子是采用运算函数有效用操作的值。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 关于译者:这是一个流淌着...

    sPeng 评论0 收藏0
  • Python数据结构

    摘要:堆栈和队列称为线性数据结构,而图形和树是非线性数据结构。在单次运行期间,可能无法遍历非线性数据结构中的所有数据项。堆栈是根据概念插入和移除的对象的容器。将元素添加到堆栈时,它被称为推送操作,而当您删除或删除元素时,它被称为弹出操作。 概述     数据结构是组织数据的方式,以便能够更好的存储和获取数据。数据结构定义数据之间的关系和对这些数据的操作方式。数据结构屏蔽了数据存储和操作的细节...

    fantix 评论0 收藏0
  • Java编程基础14——常见对象_StringBuffer&数组排序&包装类

    摘要:提供了排序,查找等功能。常用操作常用的操作之一用于基本数据类型与字符串之间的转换。 1_StringBuffer类的概述 A:StringBuffer类概述 通过JDK提供的API,查看StringBuffer类的说明 线程安全的可变字符序列 (一个类似于 String 的字符串缓冲区,但不能修改 : 不能像String那样用 + 连接来修改String) B:String...

    banana_pi 评论0 收藏0
  • Js apply()使用详解

    摘要:方法详解我在一开始看到的函数和时非常的模糊看也看不懂最近在网上看到一些文章对方法和的一些示例总算是看的有点眉目了在这里我做如下笔记希望和大家分享如有什么不对的或者说法不明确的地方希望读者多多提一些意见以便共同提高主要我是要解决一下几个问题和 Js apply方法详解我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply...

    iOS122 评论0 收藏0
  • Java快速扫盲指南

    摘要:不相等的对象要具有不相等的哈希码为了哈希表的操作效率,这一点很重要,但不是强制要求,最低要求是不相等的对象不能共用一个哈希码。方法和方法协同工作,返回对象的哈希码。这个哈希码基于对象的身份生成,而不是对象的相等性。 本文面向 刚学完Java的新手们。这篇文章不讲语法,而是一些除了语法必须了解的概念。 将要去面试的初级工程师们。查漏补缺,以免遭遇不测。 目前由于篇幅而被挪出本文的知识...

    Tony_Zby 评论0 收藏0

发表评论

0条评论

ChristmasBoy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<