前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深入理解List的toArray()方法和toArray(T[] a)方法「建议收藏」

深入理解List的toArray()方法和toArray(T[] a)方法「建议收藏」

作者头像
全栈程序员站长
发布于 2022-08-28 03:40:27
发布于 2022-08-28 03:40:27
61800
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

深入理解List的toArray()方法和toArray(T[] a)方法

这两个方法都是将列表List中的元素转导出为数组,不同的是,toArray()方法导出的是Object类型数组,而toArray[T[] a]方法导出的是指定类型的数组。

下面是两个方法的申明及说明,摘自Java8的API文档。

toArray()方法的分析

Object[] toArray() Returns an array containing all of the elements in this list in proper sequence (from first to last element). The returned array will be “safe” in that no references to it are maintained by this list. (In other words, this method must allocate a new array even if this list is backed by an array). The caller is thus free to modify the returned array. This method acts as bridge between array-based and collection-based APIs.

  • Specified by:

toArray in interface Collection<E>

  • Returns:

an array containing all of the elements in this list in proper sequence

  • See Also:

Arrays.asList(Object[\])

toArray()方法会返回List中所有元素构成的数组,并且数组类型是Object[]。还要注意一点就是,返回的数组是新生成的一个数组,也就是说,多次运行toArray()方法会获得不同的数组对象,但是这些数组对象中内容一样的。也就是说,toArray()返回的数组是安全的,你可以对它进行任意的修改,其原因就是List不会维持一个对该返回的数组的引用。下面我们做一个小实验来验证一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) { 
   
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    Object[] objects1 = list.toArray();
    Object[] objects2 = list.toArray();
    System.out.println("objects1 == objects2 : "+(objects1 == objects2));
    objects1[1]=4;
    System.out.println("show objects1: "+ Arrays.toString(objects1));
    System.out.println("show objects2: "+ Arrays.toString(objects2));
    System.out.println("show list: "+list);
}

输出结果为:

objects1 == objects2 : false show objects1: [1, 4] show objects2: [1, 2] show list: [1, 2]

从这个小实验里面,可以看出确实toArray()返回的是一个新的数组对象,并且多次执行toArray()方法获得的是不同的数组对象,并且对其中一个数组进行修改,不会影响到其他toArray()方法获得的数组,并且也不会影响到list本身原来存储的元素值。

这儿存在一个问题,list中存储的是基本类型int的包装类型Integer,如果换成其他的自定义类型呢,结果会是怎么样?接下来我们看下面这个例子。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static class People{ 
   
    String name;
    public People(String name){ 
   
        this.name = name;
    }

    @Override
    public String toString() { 
   
        return "People{" +
                "name='" + name + '\'' +
                '}';
    }
}

public static void main(String[] args) { 
   
    List<People> list = new ArrayList<>();
    list.add(new People("小明"));
    list.add(new People("小王"));
    Object[] objects1 = list.toArray();
    Object[] objects2 = list.toArray();
    System.out.println("objects1 == objects2 : "+(objects1 == objects2));
    objects1[1]=new People("小花");
    System.out.println("show objects1: "+ Arrays.toString(objects1));
    System.out.println("show objects2: "+ Arrays.toString(objects2));
    System.out.println("show list: "+list);
}

运行结果:

objects1 == objects2 : false show objects1: [People{name=‘小明’}, People{name=‘小花’}] show objects2: [People{name=‘小明’}, People{name=‘小王’}] show list: [People{name=‘小明’}, People{name=‘小王’}]

可以看到依然是和上面的分析结果一样,toArray()返回的是一个新的数组对象,对于toArray()返回的一个数组元素进行修改,不会影响到其他toArray()返回的数组对象,也不会影响list本身。

现在元素是自定义对象,那么我们对元素对象对象修改会怎么样呢?看下面这个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//People类和上一个例子中的一样,这里不再列出了。
public static void main(String[] args) { 
   
    List<People> list = new ArrayList<>();
    list.add(new People("小明"));
    list.add(new People("小王"));
    Object[] objects1 = list.toArray();
    Object[] objects2 = list.toArray();
    System.out.println("objects1 == objects2 : "+(objects1 == objects2));
    ((People)objects1[1]).name = "小花";
    System.out.println("show objects1: "+ Arrays.toString(objects1));
    System.out.println("show objects2: "+ Arrays.toString(objects2));
    System.out.println("show list: "+list);
}

输出结果:

objects1 == objects2 : false show objects1: [People{name=‘小明’}, People{name=‘小花’}] show objects2: [People{name=‘小明’}, People{name=‘小花’}] show list: [People{name=‘小明’}, People{name=‘小花’}]

从这个例子的输出结果可以看出,对元素对象本身就行修改,会导致toArray()返回的所有数组中的内容都发生改变,包括原始的list容器里面的元素类容。从这个例子可以得出,如果list.toArray()返回的数组中存放的是list原始对象的引用,只是创建了一个新的数组来装这些引用,并没有对list中原始对象进行拷贝或复制。

都已经分析到这儿了,再看一下Java内部实现的源码。首先看一下List中toArray()方法的申明:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 /** * Returns an array containing all of the elements in this list in proper * sequence (from first to last element). * * <p>The returned array will be "safe" in that no references to it are * maintained by this list. (In other words, this method must * allocate a new array even if this list is backed by an array). * The caller is thus free to modify the returned array. * * <p>This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all of the elements in this list in proper * sequence * @see Arrays#asList(Object[]) */
    Object[] toArray();

这只是一个申明,由于我们在上面的例子中使用的是ArrayList这个实现类,接下来我们再看一下ArrayList中的实现源码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** * Returns an array containing all of the elements in this list * in proper sequence (from first to last element). * * <p>The returned array will be "safe" in that no references to it are * maintained by this list. (In other words, this method must allocate * a new array). The caller is thus free to modify the returned array. * * <p>This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all of the elements in this list in * proper sequence */
public Object[] toArray() { 
   
    return Arrays.copyOf(elementData, size);
}

可以看到,在ArrayList中的实现是调用了Arrays工具类的copyOf()方法,这和ArrayLIst类中元素的存储结构相关,具体的细节就不在这里进行分析了,如果有时间的话,以后会对ArrayList这个常用的类进行一个分析。至于Arrays.copyOf()方法的作用就是上面分析的List的toArray()方法的作用了,因为toArray()本质上就是直接调用的Arrays.copyOf()方法了。

下面再来分析一下List的toArray(T[] a)方法。

toArray(T[] a)方法的分析

先看一下Java8中Api对于toArray(T[] a)方法的描述:

<T> T[] toArray(T[] a) Returns an array containing all of the elements in this list in proper sequence (from first to last element); the runtime type of the returned array is that of the specified array. If the list fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this list. If the list fits in the specified array with room to spare (i.e., the array has more elements than the list), the element in the array immediately following the end of the list is set to null. (This is useful in determining the length of the list only if the caller knows that the list does not contain any null elements.) Like the toArray() method, this method acts as bridge between array-based and collection-based APIs. Further, this method allows precise control over the runtime type of the output array, and may, under certain circumstances, be used to save allocation costs. Suppose x is a list known to contain only strings. The following code can be used to dump the list into a newly allocated array of String: String[] y = x.toArray(new String[0]); Note that toArray(new Object[0]) is identical in function to toArray()

  • Specified by:

toArray in interface Collection<E>

  • Type Parameters:

T – the runtime type of the array to contain the collection

  • Parameters:

a – the array into which the elements of this list are to be stored, if it is big enough; otherwise, a new array of the same runtime type is allocated for this purpose.

  • Returns:

an array containing the elements of this list

  • Throws:

ArrayStoreException – if the runtime type of the specified array is not a supertype of the runtime type of every element in this list NullPointerException – if the specified array is null

看着有点长哈,我在这儿进行一个简要的描述,toArray(T[] a)方法使用了泛型参数,可以返回指定类型数组,但是这个泛型在确定的时候必须是list中元素类型的父类或本身,至于那个参数数组,其实就是为了传递参数类型罢了,在给出的例子中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  String[] y = x.toArray(new String[0]);

可以清楚的看到,传进去的就是一个String 的空数组,然后返回的是list中String类型元素组成的数组。并且API中还提到,如果传进去的是new Object[]类型空数组,那么toArray(T[] a)方法就和toArray()方法相同了,我在这里猜测toArray(T[] a)方法的实现和toArray()方法应该是一样的,就不看list中的接口了,直接看ArrayList中的实现源码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** * Returns an array containing all of the elements in this list in proper * sequence (from first to last element); the runtime type of the returned * array is that of the specified array. If the list fits in the * specified array, it is returned therein. Otherwise, a new array is * allocated with the runtime type of the specified array and the size of * this list. * * <p>If the list fits in the specified array with room to spare * (i.e., the array has more elements than the list), the element in * the array immediately following the end of the collection is set to * <tt>null</tt>. (This is useful in determining the length of the * list <i>only</i> if the caller knows that the list does not contain * any null elements.) * * @param a the array into which the elements of the list are to * be stored, if it is big enough; otherwise, a new array of the * same runtime type is allocated for this purpose. * @return an array containing the elements of the list * @throws ArrayStoreException if the runtime type of the specified array * is not a supertype of the runtime type of every element in * this list * @throws NullPointerException if the specified array is null */
@SuppressWarnings("unchecked")
public <T> 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;
}

注释有点长,比较的详尽,暂时先不管注释,直接看实现的源码。从实现源码中看出,首先会判断数组a的长度和list元素的个数,进行一个比较,如果a数组的长度小于list元素个数,那么就会直接调用工具类Arrays.copyOf()方法直接进行一个拷贝,注意,这儿的是Arrays.copyOf(elementData, size, a.getClass())方法,是由元素类型参数的,就是最后一项参数,和toArray()方法实现Arrays.copyOf(elementData, size)不相同。

接着在看,如果数组a的长度length不小于list元素个数,即 a . l e n g t h &gt; = s i z e a.length &gt;= size a.length>=size得话,就会走下面的流程,首先调用System.arraycopy(elementData, 0, a, 0, size)将ArrayList里的元素数组elementData中的元素拷贝到a对象中,至于这个System.arraycopy()在这里就不详细说了。

接下来会判断一下a.length 是否大于list元素个数size,如果大于的话,会在a[size]位置设置一个null,这个设置的目的是了toArray(T[] a)方法调用者从返回的数组中检测到null时就知道后面已经没有list元素对象了。

终于分析完了,ArrayList的toArray(T[] a)源码代码证明自己上面的猜测是错的,toArray(T[] a)的实现和toArray()方法的实现很不一样,并且其实List的toArray(T[] a)方法的API说明中也提到了,如果传递进来的数组a的空间是大于list的话,就不是直接生成一个新数组来装list原来的元素对象了,而是往a数组中填,并且在最后还是放置一个null,并且在api中也说明了放置null的作用。

看来自己看的还是不够仔细,观察力还有待提升啊。同时注意个小细节,ArrayList中对于toArray(T[] a)方法的注释只是一个简要的,List中对于toArray(T[] a)方法的注释更为详尽,并且还举了例子,以后看方法注解的时候还是尽量看详尽的那一个,免得遗漏信息。

下面对这两个方法进行一个小的总结吧。

总结

List接口的toArray()方法就是直接调用Arrays.copyOf(elementData, size),将list中的元素对象的引用装在一个新的生成数组中。

List接口的toArray(T[] a)方法会返回指定类型(必须为list元素类型的父类或本身)的数组对象,如果a.length小于list元素个数就直接调用Arrays的copyOf()方法进行拷贝并且返回新数组对象,新数组中也是装的list元素对象的引用,否则先调用System.arraycopy()将list元素对象的引用装在a数组中,如果a数组还有剩余的空间,则在a[size]放置一个null,size就是list中元素的个数,这个null值可以使得toArray(T[] a)方法调用者可以判断null后面已经没有list元素了。

好了,终于分析完了!

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/146278.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
虚拟偶像的流量生意
近日,著名艺人吴某凡事件引起了全网热议,让人在拍手称快的同时,不禁感慨,追星有风险,面对人设需谨慎。
金融外参
2021/08/11
4320
虚拟偶像的流量生意
​再造“小破站”(下)——敬少年意气,也敬商业逻辑。
作者:余洁 腾讯研究院研究员 导语| 社区氛围究竟是什么?是不是一种玄学?B站的社区氛围,是基因还是人为?B站做对了些什么?内容社区,为什么选择长大而不是留在纯真年代?长大后,社区氛围就该变质吗?最后:小而美的需求去哪里满足?本文将分为上下篇破圈和溯源两部分来破一破“社区氛围”这个题。 点击阅读上篇·溯源 下篇 · 破圈 2019年9月,时值B站上市一年半。在二季度财报公布后,CEO陈睿提出,2021年B站的目标月活用户数为2.2亿。此后接受LatePost采访时,陈睿也谈到,未来一年或将降低50%的会员
腾讯大讲堂
2021/07/08
4210
虚拟偶像经济,都谁在买单?
(VRPinea 7月9日讯)小伙伴们知道王一博、吴宣仪的经纪公司乐华娱乐公司吗?近日,知名造星公司乐华娱乐旗下虚拟偶像A-SOUL成员著作权的拥有者,变更为字节跳动100%控股。这也就意味着字节跳动入局虚拟偶像已成定局,而字节和乐华的合作从商业逻辑上来说也十分合理。
VRPinea
2021/07/23
7770
虚拟偶像“C位出道”:数字浪潮下的崛起与财富密码(3/10)
在当今数字化浪潮席卷全球的时代,虚拟偶像如同一颗颗璀璨的新星,在文化娱乐的天空中闪耀着独特的光芒。从全球粉丝破亿的虚拟歌姬 “初音未来”,到国内人气爆棚的洛天依、A-SOUL 等,虚拟偶像已成为数字时代备受瞩目的文化现象,吸引着无数年轻人的关注和喜爱。
正在走向自律
2025/04/12
3380
虚拟偶像“C位出道”:数字浪潮下的崛起与财富密码(3/10)
直播一小时营收破百万!虚拟主播说英文在B站疯狂吸金,背后企划公司IPO作价23亿
丰色 鱼羊 发自 凹非寺 量子位 | 公众号 QbitAI 直播不到2小时,就挣了111多万??? 这么一位首播即登B站实时热门第一的主播,甚至不是真人形象。 他直播的状态基本是酱婶的: 并且尽管全程英文,他直播间当晚的付费率还是达到了惊人的73.3%,跟第二名差出去近62个百分点。 △图源:B站@V面观测中心 也就是说,每10个进入直播间跟主播互动的人里,就有超过7个人为他花了钱! 整场直播的画风,大概就是这样的… 昨天的中国富婆:听不懂你在说什么所以用礼物铺满屏。 这个虚拟主播,究竟什么来头?
量子位
2022/05/09
1.2K0
直播一小时营收破百万!虚拟主播说英文在B站疯狂吸金,背后企划公司IPO作价23亿
元宇宙点燃了虚拟偶像?
2021年,元宇宙概念在投资市场中迅速走红,群聚效应明显增强,多个企业纷纷加码元宇宙赛道。3月份,元宇宙概念第一股Roblox在纽交所正式上市;8月份,字节跳动收购Pico,入局VR行业;10月份,Facebook正式改名为Meta,一举进击元宇宙......
刘旷
2021/11/05
6560
全球首个 AI 说唱歌手 TikTok 发新歌,虚拟偶像正当时
内容提要:虚拟歌手正在从二次元破圈,走进大众视野。随着人工智能技术的发展,它们的形象与作品也愈加丰富、立体。虚拟偶像,正在成为人工智能技术催生下的新一代偶像。
HyperAI超神经
2021/03/25
8560
全球首个 AI 说唱歌手 TikTok 发新歌,虚拟偶像正当时
VDLive虚拟主播系统实用操作:如何做一场真人+动漫人物的有趣直播?
2020年是直播带货的元年,各种玩法层出不穷,为了能够在这个大热风口谋得一杯羹,各行各业使出了浑身解数。5G的到来,技术的进步,更是给直播行业带来全新玩法。
用户9569216
2022/03/17
2.5K0
VDLive虚拟主播系统实用操作:如何做一场真人+动漫人物的有趣直播?
互联网巨头灌溉,虚拟偶像市场开花
近期,天猫官宣新代言人是易烊千玺的首个个人虚拟形象“千喵”。消息一出,该官宣微博已经有高达100w+的转发量,“易烊千玺虚拟形象代言天猫”的话题,阅读量近33亿,讨论量达523.8w。
刘旷
2020/10/13
8160
出道即成现象级虚拟主播,令颜欢做对了什么?
2023年,ChatGPT点燃了科技圈的第一把火,包括微软、谷歌、百度、阿里、字节在内的国内外科技巨头均在加码生成式AI,AIGC再度成为行业焦点。其实在一众巨头开发类ChatGPT应用前,用技术生成内容的商业模式就已在一些领域出现,其中虚拟主播就已在B站、抖音等平台风靡,大有成为头部主播类目的势头。来自B站的数据就显示,2022年就有23万名虚拟主播在平台开播,同比增长190%。
罗超频道
2023/02/27
2.3K0
出道即成现象级虚拟主播,令颜欢做对了什么?
超V对话:详解虚拟主播Vtuber的制作与IP打造
5月15日,由VR陀螺、天翼云VR、人民网5G创新中心联合推出的国内首档VR虚拟访谈节目《超V对话》第三期正式播出,该节目由VSWORK虚拟空间提供技术支持。(特别鸣谢超次元为本期节目提供虚拟角色)
VRPinea
2020/05/26
2.9K0
电商直播风暴来了,AI虚拟偶像彻底革命李佳琦、薇娅?
虽说在电商直播时代“万物皆可卖,人人皆可播”,但在KOL、明星、企业家等一一下场直播卖货之后,AI虚拟偶像直播卖货仍显得独树一帜。
刘旷
2020/05/12
7480
电商直播风暴来了,AI虚拟偶像彻底革命李佳琦、薇娅?
从草原来的虚拟人「奶思」火了,虚拟代言人的未来有多可期?
机器之心原创 作者:蛋酱 当数字虚拟人赛道越来越卷,品牌方只有获得了低成本的一站式解决方案,才能告别「重复造轮子」的实验,让虚拟人更高效地落地。 最近,一位叫「奶思」的虚拟人主播火了。 才一出场,奶思的颜值就征服了众人:尽管虚拟人普遍五官精致、气质脱俗,但像奶思这样独特的「民族风」虚拟人,还真是第一次见。 12 月 12 日上午,蒙牛在微博官方发布了奶思形象图,并预告了当晚奶思即将迎来直播首秀。 在双十二直播当天,快手官方虚拟主播关小芳、虚拟歌手神奇少女张凤琴、快手火力营营长关箭、百度 AI 数字人希加加
机器之心
2023/03/29
1.1K0
从草原来的虚拟人「奶思」火了,虚拟代言人的未来有多可期?
B 站人气 Top2 AI 主播“羊驼-阿花”何以拥有“高智商、高情商”?
如果你是 B 站用户,那你肯定知道“羊驼 - 阿花”这个人气主播,它是一款由“虚拟偶像女团 A-SOUL”背后的虚拟娱乐公司“枝江娱乐”打造的一款 AI 主播产品,其动物的外形 + 萝莉声线,一经推出便迅速走红网络,甚至一跃成为 B 站人气 Top2 的流量 AI 明星。
深度学习与Python
2024/01/23
1610
B 站人气 Top2 AI 主播“羊驼-阿花”何以拥有“高智商、高情商”?
B站成映客基石投资者,直播与二次元天然一对?
爱奇艺、B站、虎牙、优信二手车、华米、平安好医生等公司已先后上市;小米确定7月9日敲钟,“罗超频道”已受邀到现场观摩敲钟仪式。与此同时,映客、拼多多、同程艺龙、猎聘网、华兴资本、指尖跃动、多益网络等公司也正在向资本市场发起冲刺。而腾讯音乐、斗鱼、快手、一下科技等则传出过将要上市的消息。新经济公司密集上市,是互联网行业蓬勃发展进入收割季的现象,也意味着这一波上市潮可能会是新经济公司上市的末班车。
罗超频道
2018/07/23
6920
B站成映客基石投资者,直播与二次元天然一对?
我和虚拟偶像做同事
当大众对元宇宙尚处于懵懂状态时,看得见的虚拟偶像们便成了连接现实世界的桥梁,填补了对元宇宙的想象空白。
镁客网
2022/02/10
8110
我和虚拟偶像做同事
国内首个“虚拟数字人影响力指数”亮相,中国传媒大学发布《中国虚拟数字人影响力指数报告》
  1 月 27 日,中国传媒大学媒体融合与传播国家重点实验室媒体大数据中心联合头号偶像共同发布《中国虚拟数字人影响力指数报告》,国内首个“虚拟数字人影响力指数”亮相。
科技旋涡
2022/03/30
4510
国内首个“虚拟数字人影响力指数”亮相,中国传媒大学发布《中国虚拟数字人影响力指数报告》
数字人深度报告!元宇宙下的爆火概念,技术和应用一文看懂
虚拟数字人指存在于非物理世界中,由计算机手段创造及使用,并具有多重人类特征(外貌特征、人类表演能力、交互能力等)的综合产物。虚拟数字人可按人格象征和图形维度划分,亦可根据人物图形维度划分。人物形象、语音生成模块、动画生成模块、音视频合成显示模块、交互模块构成虚拟数字人通用系统框架。
科技旋涡
2022/03/30
1.6K0
数字人深度报告!元宇宙下的爆火概念,技术和应用一文看懂
一文带你了解AI虚拟数字人!
据艾媒咨询,2025年中国虚拟人市场规模预计达480.6亿元,用户群体主要为中型及小微型企业,产品需求量TOP5分别是电商、卫生、社会保障和社会福利业、教育、金融和运输业,主要产品类型为数字员工及定制化数字人。
朱晓霞
2024/03/14
13.7K1
一文带你了解AI虚拟数字人!
今天这个「主播」,有点不一样!
---- 新智元报道   编辑:好困 【新智元导读】万物皆可播,人人皆主播。不过现在直播间里和你对话的可不一定是个「真人」了哦。 直播带货,这有啥新鲜的? 别急,今天给你来点儿不一样的。 请看上面这两位长相差不多的主播,像不像是一对双胞胎? 但实际上,她们是「同一个人」! 至于原因,这里先卖个关子。 半夜还要直播,太「费人」了吧 我们先说说直播带货这件事。 顾名思义,重点就是为了「带货」。 但每次都要卡着点进去,一不小心就会错过。 一来二去,可能也就不想再看了。 商家们似乎也发现了这个问题,于是虚拟带
新智元
2022/05/17
1.6K0
今天这个「主播」,有点不一样!
推荐阅读
相关推荐
虚拟偶像的流量生意
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档