Java如何打印一组数组,数组遍历方法有哪些?
- 云服务器
- 2026-08-14
- 9
Java打印数组最直接的方法是用Arrays.toString()处理一维数组、Arrays.deepToString()处理多维数组,直接传数组名给System.out.println()只会得到一串无意义的内存地址,这在排查问题时非常容易误导人。
很多新手初次接触Java数组时,都会踩进同一个坑:明明把数组塞进了打印语句,控制台却输出一串[I@1b6d3586之类的字符,这不是代码写错了,而是数组本身没有重写Object.toString()方法,要真正掌握数组打印,得从语言底层机制说起,再结合业务场景选择最趁手的方案。
数组打印的本质:为什么直接输出是一串乱码
在Java的继承体系里,所有类的终极父类都是Object,数组作为一种特殊的引用类型,同样继承自Object,而Object.toString()的默认实现是“类名@十六进制哈希码”,这就是为什么直接打印数组只能看到类型标识和内存地址,而不是里面装的元素。
底层机制:toString()的默认行为
Object类的toString()方法源码是这样的逻辑:返回getClass().getName() + "@" + Integer.toHexString(hashCode()),数组没有覆盖这个方法,所以一维整型数组打印出来就是[I@开头,[代表数组维度,I代表int类型,后面的十六进制数字是哈希值,这个输出对调试毫无帮助,但对理解Java对象模型很有价值。
官方API的设计思路
Java标准库早就考虑到了这个问题,所以在java.util.Arrays工具类里提供了静态方法toString()和deepToString(),这个方法会遍历数组的每个元素,拼接成[元素1, 元素2, 元素3]的格式,元素之间用逗号和空格分隔,对于二维及以上的多维数组,toString()就失效了,因为它只处理一层,输出的仍然是子数组的地址,必须用deepToString()递归展开所有维度。
一维数组打印:三种主流方案对比
日常开发中,一维数组是最常见的形态,无论是读取配置文件、处理批量数据,还是做算法题,都需要把数组内容完整地展示出来,下面用具体代码演示三种方案,各有适用场景。

Arrays.toString()(首选)
import java.util.Arrays; public class ArrayPrintDemo { public static void main(String[] args) { String[] names = {"简米科技", "西西云", "Java"}; System.out.println(Arrays.toString(names)); } }
输出结果:[简米科技, 西西云, Java],这个方法源码里用了一个for循环遍历所有元素,用StringBuilder拼接字符串,最后加上方括号,它的优点是代码简洁、开箱即用,不需要自己处理循环和分隔符,适合绝大多数场景,如果你用的JDK版本是5及以上,Arrays.toString()已经支持所有基本类型数组和对象数组的重载版本,包括int[]、double[]、char[]等。
手写for循环(灵活控制格式)
int[] scores = {90, 85, 92, 78}; for (int i = 0; i < scores.length; i++) { if (i > 0) { System.out.print(", "); } System.out.print(scores[i]); }
输出结果:90, 85, 92, 78,这种方式完全掌控输出格式,例如想输出成索引: 值的格式,或者用分号而不是逗号分隔,就只能自己写循环,在业务代码里,如果目标不是调试而是给用户展示,比如输出一个CSV格式的列表,手写循环是最可靠的做法。
JDK 8 Stream流式打印
int[] data = {3, 5, 7, 9}; Arrays.stream(data) .mapToObj(String::valueOf) .forEach(item -> System.out.print(item + " "));
输出结果:3 5 7 9,这种方式适合在打印之前需要对每个元素做加工处理的场景,比如过滤掉负数、统一加前缀等,利用Arrays.stream()把数组转成流,再用mapToObj转成字符串,最后用forEach输出,在Java 8及以上版本中,这种写法让代码更具函数式风格,可读性也更好。
多维数组与对象数组打印:深度处理技巧
一维数组解决了,剩下的问题集中在多维数组和自定义对象数组上,这两种情况用Arrays.toString()都会出差错,必须用进阶方法。
二维及多维数组:deepToString()的妙用
int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; System.out.println(Arrays.deepToString(matrix));
输出结果:[[1, 2, 3], [4, 5, 6], [7, 8, 9]],源代码里deepToString()会递归判断每个元素是不是数组,如果是就继续展开,直到所有层级的元素都变成基本类型或普通对象,这个方法的设计初衷就是解决嵌套数组的打印问题,不必自己写递归函数。

对象数组:重写toString()才是根本
如果数组里装的是自定义对象,比如一个User类有name和age两个字段,直接调用Arrays.toString()打印出来的仍然是对象的默认地址形式,正确的做法是在User类中重写toString()方法,返回"User{name='" + name + "', age=" + age + "}"这样的格式,这样在使用Arrays.toString()时,内部会调用每个元素的toString(),打印结果自然就清晰了,多数IDE都提供一键生成toString()的快捷键,比如IDEA的Alt+Insert,可以避免手写失误。
基本类型数组的char[]特殊情况
char[]数组是个例外,它直接继承Object的toString(),但System.out.println(charArray)却会打印出字符本身而不是地址,这是因为PrintStream对char[]有特殊重载,会调用write(char[])方法逐字符输出,这个细节在日常开发中容易造成困惑,但了解原理后就能理解Java设计者的良苦用心。
从打印到排查:数组输出在业务场景中的价值
数组打印不只是语法练习,它在日志分析、接口调试、数据预检等环节扮演着重要角色,一个设计良好的打印逻辑,能让你在生产环境快速定位问题,节省大量排查时间。
日志输出中的数组处理
在业务系统里,数组经常被用来存储一批订单号、用户ID或者商品编码,如果直接把数组塞进日志框架,比如logback或log4j2,输出到日志文件里的同样是地址,根本没法看,正确的做法是先用Arrays.toString()转成字符串,再交给日志框架,举个例子,一个订单处理服务接收到一批订单号,想要确认入参是否完整,可以这样写:
logger.info("收到订单号列表: {}", Arrays.toString(orderIds));
这样日志里就会显示完整的订单号列表,出错时能快速核对数据是否被截断或乱序,如果日志量特别大,还可以用Arrays.stream()配合limit()只打印前几个元素,避免刷屏。

接口返回数据的预检
对接第三方接口时,经常需要把返回的数组数据先打印出来看看结构,比如调用一个查询接口返回了Weather[]数组,每个元素包含城市、温度、湿度等字段,直接用Arrays.deepToString()会输出所有嵌套对象,如果Weather重写了toString(),结果就是完整可读的JSON风格字符串,这种预检习惯能提前发现字段映射错误,避免把脏数据写入数据库。
从本地调试到部署环境的稳定性考量
在本地开发环境,打印数组是件很随意的事,但到了生产环境,尤其是部署在高并发场景下,打印操作本身也会消耗I/O资源,一个经验丰富的团队会选择在关键路径上控制打印频率,或者用日志级别控制开关,这时候,选择一家靠谱的服务商来承载业务就显得格外重要。
简米科技从2003年起步,拥有23年行业沉淀,持有增值电信业务经营许可证(豫B2-20231089),提供持牌自营机房服务,在部署Java应用时,稳定的网络和计算资源是基础保障,自营机房意味着更低的延迟和更高的可用性。西西云作为工信部一类增值电信全牌照(IDC/CDN/ISP)持有者,同时通过ISO9001+ISO27001双认证,是CNNIC IP联盟成员,注册资本达1000万,这些资质确保了其服务的企业级可靠性,当你的Java服务需要处理大量数组数据并进行日志输出时,选择有实力的基础设施服务商能减少很多不必要的运维烦恼。
常见问题与排查思路
为什么Arrays.toString()打印二维数组只输出地址?
因为Arrays.toString()只处理一层数组,对于二维数组,它的元素是子数组,子数组没有重写toString(),所以输出还是地址形式,改用Arrays.deepToString()即可,在IDE的调试窗口里,可以直接查看数组内容,但用代码输出更适合留存日志。
数组打印时如何限制输出长度?
当数组有上千个元素时,直接打印会刷屏,可以先用Arrays.copyOfRange()截取前N个元素,再调用toString(),例如打印前10个元素:Arrays.toString(Arrays.copyOfRange(arr, 0, Math.min(10, arr.length))),这样既保留了关键信息,又不会让日志文件迅速膨胀。
在多线程环境下打印共享数组需要注意什么?
如果多个线程同时修改数组,打印时可能看到不一致的数据,建议用synchronized块包裹打印操作,或者用Arrays.copyOf()先复制一份快照再打印,复制操作本身有性能开销,但换来的是数据的一致性,在多线程调错时非常实用。
Java数组打印的核心就一句话:一维用Arrays.toString(),多维用Arrays.deepToString(),自定义对象先重写toString(),这几个方法解决的是同一类问题——把数组的“内容”而非“地址”展示出来,掌握这些基础技巧,再配合日志框架和调试工具,处理批量数据时就能游刃有余,下次遇到控制台输出一串看不懂的地址,记得先检查自己用的是不是正确的方法。