一、用法
toString()
方法其实很好理解。to
:变成,String
:字符串,合在一起就是:变成字符串。
public String toString() //返回该对象的字符串表示形式(可以看做是对象的内存地址值)
代码示例
Object obj = new Object();
String str1 = obj.toString();
System.out.println(str1); // java.lang.Object@119d7047
程序运行完毕,可以发现它把对象变成了这种字符串:java.lang.Object@119d7047
。
这种字符串它其实是有规律的,可以分成三段,以中间的 @
为中心:前面是 包名 + 类型
,@
自己本身是一个固定格式,@
后面的一堆就是对象的地址值。
如果我创建的不是 Object类
的对象,而是其他类的对象,其实也是这样的。
Student.java
public class Student {
private String name;
private int age;
// 无参构造、有参构造、get、set方法
}
注意这里,我没有让 Student 去继承其他的类,因此它默认就继承 Object。
运行下面代码,可以发现它也是这种 包名 + 类名 @ 对象地址值
Student stu = new Student();
String str2 = stu.toString();
System.out.println(str2);//com.itheima.a04objectdemo.student@4eec7777
这里我可以简单带大家去看一下 Object
的源代码。
选中 Object类名
ctrl + b 跟进,再按快捷键ctrl + F12 搜一下 toString()
然后回车。
1、中间的 @
是固定格式
2、前面的 getClass().getName()
就可以获取它的 包名 + 类名
3、后面的 Integer.toHexString(hashCode());
就可以获取到 对象的地址值
但是这个地址值获取到不是直接给你的,而是经过一系列的复杂运算,然后将它变成 16进制
。
但是现在我们可以把 Integer.toHexString(hashCode())
简单的理解成是 对象的地址值
。
getClass().getName() + "@" + Integer.toHexString(hashCode());
再往下可以去跟大家说一个小小的细节:
如果在打印 stu
的时候没有去调用 toString()
方法,而是直接打印一个对象。
你就会发现,你看到的效果其实是一样的
Student stu = new Student();
String str2 = stu.toString();
System.out.println(str2);//com.itheima.a04objectdemo.student@4eec7777
//细节:
System.out.println(stu);//com.itheima.a04objectdemo.student@4eec7777
那为什么是这样的呢?这时我就带着你去认识一下输出语句。
二、输出语句
输出语句 System.out.println()
分为三部分:
1、System
:我们刚刚学习过,它是Java里面的一个类名
选择 System类名
,ctrl + b 跟进,往下找,可以发现:out
是 System类
中的一个静态变量
因此在代码中,我们就可以通过类名直接调用静态变量 System.out
。
out
的初始值是 null
,但是在下面会给 out
赋值。
out
的类型是 PrintStream
,这个类在我们后面学习 IO流
的时候会再次细说。
现在我们可以先简单理解 System.out
就是:类型.静态变量
,这样它就可以获取到打印的对象
获取到 打印的对象
后,就可以用这个对象,去调用 println()
方法,方法里面的参数就表示我们要打印的内容。
我们可以选中这里的 println()
,ctrl + b 看下源码:
如果你传递了一个对象进来,首先它会调用 String类
中的 valueOf()
静态方法,把对象传递进去
String s = String.valueOf(x);
valueOf()
是一个关键点,ctrl + b 跟进,可以看见它在底层做了一个这样的判断:判断对象为不为空,如果为空,返回字符串 "null
,如果不是空,就会使用对象去调用 toString()
方法,即将对象变成了:包名 + 类名 + @ + 地址值
的形式。
ctrl + alt + ← 回到上一步,因此方法的第一行其实就是将传递过来的对象
变成了字符串
,在底层调用了 toString()
方法。
有了这个字符串后,下面它就会去调用其他的方法将这个字符串打印出来。
选中 writeln()
方法跟进,这个方法里面其实是有两个核心点的:
① 720行:textOut.write(s);
其实就是将对象的字符串进行打印
② 721行:textOut.newLine();
其实就是做了一个换行处理
这些其实就是输出语句的核心逻辑
总结:当我们打印一个对象的时候,底层会调用对象的 toString()
方法,把对象变成字符串,然后再打印在控制台上,打印完毕后换行处理。
三、引出 重写toString()方法
知道这个结论后,就需要思考了:
默认情况下因为 Object类
中的 toString()
方法返回的是地址值。所以默认情况下打印一个对象打印的就是地址值。
但是地址值对我来讲是没有意义的,如果我不想看到地址值,而是看到对象内部的属性值,那应该怎么办呢?
在之前我们学习继承的时候曾经说过:父类里面的方法如果不能满足当前的要求,就可以重写该方法。
解决办法:重写父类中的 toString()
方法即可。
当我直接在 Student类
中写 toString()
时,选择第二个 toString()
然后回车,此时IDEA就会问你:你要不要将两个对象的属性值拼在里面?
但是它的这种拼接方式,稍微有一点难。
这里我将它改写一下,这样子看上去就非常的清爽了。
public String toString() {
return name + ", " + age;
}
现在我已经对 toString()
方法进行了重写,那此时我再次打印 stu变量
的时候,它显示的还是地址值吗?
程序运行完毕,可以发现它打印的就是对象内部的属性值。
Student stu = new Student("张三", 23);
System.out.println(stu); // 张三, 23
四、快捷方式
其实这个书写的代码不需要我们自己去写,之前跟大家分享过 Ptg
插件,我们可以用 Ptg
自动去完成。
当我们写完私有化成员变量后,下面直接右键 ——> Ptg To JavaBean
往下滑,可以发现插件自动帮我们拼接好了。
回到测试类中,右键Run
Student stu = new Student("张三", 23);
System.out.println(stu); // Student{name = 张三, age = 23}
五、总结
如果我们打印一个对象,想要看到属性值的话,那么就重写 toString()
方法即可。
在重写的方法中把对象的属性进行拼接即可。