当前位置: 首页 > 科技观察

如何优雅地打印Java对象?

时间:2023-03-14 23:39:55 科技观察

大家好,我是沉默王二,一个和黄家驹一样高,和刘德华一样帅的程序员。写了十多年的Java代码,我仍然觉得自己是个菜鸟(请允许我感到羞耻)。在一个风雨交加的黑夜,想了想,我觉得不能再这样浪费时间了。于是他下定决心,准备用输出之法强行输入,以此来修炼内功,从而进阶成为真正的高手。同时也希望这些文章能够帮助到更多的读者,让你在学习的路上不再孤单、空虚、冰冷。为了更好的输入,我选择StackOverflow作为前线对战,毕竟很多前辈都在强烈推荐。在本文中,我们将讨论如何优雅地打印Java对象。没想到这道题的访问量高达阿尔泰山,总访问量29万+。这难以置信!说明很多很多的程序员都被这个问题困扰过。让我们回顾一下提问者的问题。提问者定义了这样一个类:publicclassCmower{privateStringname;publicCmower(Stringname){this.name=name;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}}然后创建了一个类,并且尝试打印它:Cmowercmower=newCmower("SilenceKingTwo");System.out.println(cmower);但是输出的并不是他想要的:com.cmower.java_demo.stackoverflow.printObject.Cmower@355da254另外他在打印数组的时候也遇到了类似的问题:Cmower[]cmowers={newCmower("SilenceKingTwo"),newCmower("沉默王三")};System.out.println(cmowers);输出是:[Lcom.cmower.java_demo.stackoverflow.printObject.Cmower;@4dc63996Cmower@355da254和[LCmower;@4dc63996输出是什么意思?如何打印Cmower类的名称呢?以及如何打印对象列表(数组或集合)?如果你曾经被这样的问题困扰过,或者正在被困扰,请跟我来,让我们并肩携手,一起梳理这个问题,找到精彩的答案。DuangDuangDuang来打怪兽吧!01.发生了什么?默认情况下,所有Java对象都带有toString()方法。当我们尝试打印此对象时,将调用此方法。System.out.println(object);//调用object.toString()toString()方法是由Object类(所有Java对象的超类)定义的,它返回一个看似晦涩难懂的字符串:1)类名,组成包名和类名的组合,例如com.Cmower;2)@连接器;3)十六进制哈希码。我们看一下这个方法的源码:publicStringtoString(){returngetClass().getName()+"@"+Integer.toHexString(hashCode());}数组和普通的Java对象类似,只有一点点不同-跟踪Class类的getName()方法可以证实这一点。如果此类对象表示一类数组,则名称的内部形式由元素类型的名称和一个或多个表示数组嵌套深度的“[”字符组成。对于数组,Class名前会有一个或多个英文括号“[”,表示数组的维数(一个“[”表示一维数组,两个“[”表示二维数组),后跟元素的类型首字母。这就是对象数组以“[L”为前缀的原因。有没有恍然大悟的感觉?02.自定义输出如果你想在打印时输出你期望的结果,你必须重写自定义类中的toString()方法,看一个例子。publicclassCmower{privateStringname;//省略构造函数和getter/setter@OverridepublicStringtoString(){returnname;}}当我们再次打印Cmower对象时,输出结果不再是com.Cmower@355da254。SilentKingII但是这个结果并不能让我们满意,有点突兀,不能表达对象的类型。更优雅的做法是这样的:publicclassCmower{privateStringname;//省略构造函数和getter/setter@OverridepublicStringtoString(){returngetClass().getSimpleName()+"[name="+name+"]";}}再次打印Cmower对象,输出结果为:Cmower[name=SilentWangEr]这个表格不仅看起来很漂亮,而且在调试时也能给出有用的信息。但是,有时候我们不想重写toString()方法(我们想保留原来的打印格式ClassType@123121),又想打印对象的信息,那么最好定义一个新的方法,比如作为toMyString()方法。03.自动输出IDE(Eclipse或IntelljIDEA)通常会为类的字段提供一种输出格式,用于重写toString()方法。@OverridepublicStringtoString(){return"Cmower{"+"name='"+name+'\''+'}';}另外,一些开源的第三方库也会提供这样的功能,例如:1)ApacheCommonsLang的ToStringBuilder。使用方法:@OverridepublicStringtoString(){returnToStringBuilder.reflectionToString(this);}输出结果:com.cmower.printObject.Cmower@355da254[name=SilenceKing2]2)GoogleGuava的MoreObjects使用方法:@OverridepublicStringtoString(){returnMoreObjects.toStringHelper(this).add("name",getName()).toString();}输出结果:Cmower{name=沉默王二}3)Lombok的@toString注解(IDE需要安装Lombok插件-infirst)touseMethod:@ToStringpublicclassCmower{privateStringname;//省略构造函数和getter/setter}只需要一个@toString注解,不需要重写toString()方法。输出结果:Cmower(name=silentking2)04.打印对象列表(数组或集合)以上内容已经说明了单个对象的打印,你还好吗?接下来说说打印对象列表Son。1)数组Arrays.toString()可以将任何类型的数组转换成字符串,包括基本类型数组和引用类型数组。代码示例如下。Cmower[]cmowers={newCmower("沉默王二"),newCmower("沉默王三")};System.out.println(Arrays.toString(cmowers));输出结果:[Cmower{name='沉默王二'},Cmower{name='沉默之王三'}]2)Collection对于一个collection,可以直接打印出来,输出我们预期的结果。代码示例如下。Listlist=newArrayList<>();list.add(newCmower("沉默之王二"));list.add(newCmower("沉默之王三"));System.out.println(list);输出结果:[Cmower{name='沉默王二'},Cmower{name='沉默王三'}]05.谢谢亲爱的读者,以上就是本文的全部内容。疫情期间能坚持看技术文章,二哥一定要给你点个赞,给你个赞。