5.2 Object类中两个需要被重写的方法
两个需要重写的Object类的方法
1、toString()方法:返回getClass().getName()+'@'+Integer.toHexString(hashCode()
对于String类已经重写了toString()方法,该方法返回字符串的内容;
对于一般类自定义重写该方法,使其返回用户关注的关键成员信息;
2、equals(Object obj)方法:用于比较两个引用变量是否相等,必须指向同一块内存区才会相等。
对于String类有两点需要注意:
(1)String类已经重写了equals()方法,只需要String类型的变量的字符串内容相同,则输出true
(2)在编译时可以确定字符串内容的String类型的引用变量,数据管理在常量池中,否则放在堆内存中。
一、打印对象和toString()方法
toString()方法是Object类中的一个实例方法,所有Java都是Object类的子类,因此所有Java对象都具有toString()方法。
public String toString()返回对象的字符串表示形式。通常,toString方法返回一个字符串,该字符串“以文本形式表示”该对象。
参数:无参数
返回值:实例的类名+@+对象哈希值的无符号十六进制。即getClass().getName()+'@'+Integer.toHexString(hashCode())
hashcode()返回此对象的哈希值
hashCode的规则:
★每当在Java应用程序的执行过程中多次对同一对象调用hashCode方法时,hashCode方法必须一致地返回相同的整数,前提是对象的equals比较中使用的信息未被修改。从
应用程序的一次执行到同一应用程序的另一次执行,此整数不必保持一致。
★如果根据equals(Object)方法,两个对象相等,那么对两个对象中的每个对象调用hashCode方法必须产生相同的整数结果。
★根据equals(java.lang.Object)方法,如果两个对象不相等,则对这两个对象中的每一个调用hashCode方法都必须产生不同的整数结果。
1 class Person 2 { 3 private String name; 4 public Person(String name) 5 { 6 this.name=name; 7 } 8 @Override//重写hashcode方法 9 public int hashCode() 10 { 11 return 200; 12 } 13 } 14 15 public class PersonTest 16 { 17 public static String getType(Object obj) 18 { 19 return obj.getClass().toString(); 20 } 21 public static void main(String[] args) 22 { 23 var p=new Person("孙悟空"); 24 System.out.println(p); 25 System.out.println(getType(p)); 26 System.out.println(p.toString()); 27 System.out.println(getType(p.toString())); 28 } 29 } 30 ---------- 运行Java捕获输出窗 ---------- 31 Person@c8 32 class Person 33 Person@c8 34 class java.lang.String 35 36 输出完成 (耗时 0 秒) - 正常终止
所有Java对象都可以和字符串进行连接运算,当Java对象和字符串进行连接运算时,系统会自动调用Java对象toString()方法的放回置和字符串进行连接运算,及下面代码输出结果完全相同
var pStr=p+"";
var pStr=p.toString()+"";
重写toString()方法——toString()方法是一个“自我描述“方法,用于概述外界对象的状态信息。但是Object()方法总是返回对象的实现类的”类名+@+hashCode值“,这个值并不能很好地描述对象的信息。因此如果需要了解对象的”自我描述信息“的功能,就必须重写Object类的toString()方法。
String类已经重写了toString()方法,该方法返回字符串的内容:
1 class Test 2 { 3 public void info() 4 { 5 System.out.println("这是一个Test类"); 6 } 7 } 8 class StringToString 9 { 10 public static void main(String[] args) 11 { 12 String str1="abc"; 13 System.out.println(str1.toString()); 14 15 var t=new Test(); 16 System.out.println(t.toString()); 17 } 18 } 19 class Test 20 { 21 public void info() 22 { 23 System.out.println("这是一个Test类"); 24 } 25 } 26 class StringToString 27 { 28 public static void main(String[] args) 29 { 30 String str1="abc"; 31 System.out.println(str1.toString()); 32 33 var t=new Test(); 34 System.out.println(t.toString()); 35 } 36 } 37 ---------- 运行Java捕获输出窗 ---------- 38 abc 39 Test@8efb846 40 41 输出完成 (耗时 0 秒) - 正常终止
重写toString()方法总是返回该对象的所有令人感兴趣的信息所组成的字符串。通常返如下格式的字符串:
1 类名[field1=值1,field=值2,...]
例子:
1 class Apple 2 { 3 protected String color; 4 protected double weight; 5 6 public Apple() 7 { 8 9 } 10 public Apple(String color,double weight) 11 { 12 this.color=color; 13 this.weight=weight; 14 } 15 16 @Override 17 //形参列表、方法名相同,抛出异常更小,返回值类型更小,访问权限更大 18 public String toString() 19 { 20 return "Apple[color="+color 21 +","+"weight="+weight+"]"; 22 } 23 } 24 class AppleTest 25 { 26 public static void main(String[] args) 27 { 28 var ap=new Apple("red",2.5); 29 System.out.println(ap.toString()); 30 31 } 32 } 33 ---------- 运行Java捕获输出窗 ---------- 34 Apple[color=red,weight=2.5] 35 36 输出完成 (耗时 0 秒) - 正常终止
二、==和equals方法
Java程序测试两个变量是否相等有两种方式:一种是利用equals()方法(针对引用变量),一种是==运算符。
对于数值类型变量,只需要两个变量的值相等,就放回true.
对于两个引用变量类型,只有当它们指向同一个对象时,==才会返回true。==不可以用于比较类型上没有父子关系的两个对象。
1 class Test 2 { 3 public String name; 4 public Test(String name) 5 { 6 this.name=name; 7 } 8 } 9 class EqualsTest 10 { 11 12 public static void main(String[] args) 13 { 14 //数值类型变量比较 15 int i1=5; 16 float f1=5.0f; 17 System.out.println(i1==f1);//输出true 18 19 //包装类比较 20 Integer num1=2; 21 Integer num2=2; 22 System.out.println(num1==num2);//输出true 23 System.out.println(num1.equals(num2));//输出true 24 25 Integer num3=128; 26 Integer num4=128; 27 System.out.println(num3==num4);//输出false 28 System.out.println(num3.equals(num4));//输出true 29 30 //内部内的比较 31 Test t1=new Test("孙武"); 32 Test t2=new Test("孙武"); 33 System.out.println(t1==t2);//输出false 34 System.out.println(t1.equals(t2));//输出false 35 } 36 }
注意:String str="Hello"直接量和var str=new String("Hello")的区别:
当程序直接使用"Hello"字符串直接量(包括在编译时就可以计算出来的字符串值)时,JVM将会使用常量池来管理字符串;当使用new("Hello")时,JVM先使用常量池来管理”Hello“直接量,再调用String类构造器来创建一个新的String对象,新创建的String对象将会被保存在堆内存中。换言之,new("Hello")一个产生两个字符串对象。
常量池:专门用于管理在编译时被确定并被保存在已编译的.class文件中的一些数据。它包括类、方法、接口中的常量。还包括字符串的常量。
示例JVM使用常量管理池管理字符串直接量的情形:
1 class StringCompareTest 2 { 3 public static void main(String[] args) 4 { 5 //s1直接引用常量池的“疯狂Java” 6 var s1="疯狂Java"; 7 var s2="疯狂"; 8 var s3="Java"; 9 10 //s4后面的字符串可以在编译时就确定下来 11 //s4直接引用常量池中的"疯狂Java" 12 var s4="疯狂"+"Java"; 13 14 //s5后面的字符串可以在编译时就确定下来 15 //s5直接引用常量池中的"疯狂Java" 16 var s5="疯"+"狂"+"Java"; 17 18 //s6后面的字符串可以在编译时不可以确定下来 19 //不能引用常量池中的字符串 20 var s6=s2+s3; 21 22 //使用new()调用构造器将会创建一个String对象 23 //S7引用堆内存中创建的String对象 24 var s7=new String("疯狂Java"); 25 26 System.out.println(s1==s4);//输出true 27 System.out.println(s1==s5);//输出true 28 System.out.println(s1==s6);//输出false 29 System.out.println(s1==s7);//输出false 30 System.out.println(s6==s7);//输出false 31 32 } 33 }
JVM常量池保证相同的字符串直接量只有一个,不会产生多个副本。例如s1,s4,s5都将引用常量池的同一个字符串对象。
改写equals()方法:
equals()方法是Object类提供的实例方法,因此所有的引用变量都可以调用该方法来判断是否与其引用变量相等。但该方法判断两个对象是否相等的标准与使用==运算符没有区别,同样要求两个引用变量指向同一个对象才会返回true。因此Object类提供的equals()方法没有太大的实际意义,因此希望自定义相等的标准,则需要重写equals()方法。
提示:String以及重写了Object的equals()方法,String的equals()方法判断两个字符串是否相等的标准是:只要两个字符串所包含的字符串序列相同,通过equals()比较将返回true,否则返回false。
1 class StringEquals 2 { 3 public static void main(String[] args) 4 { 5 String s1="疯狂"; 6 String s2="Java"; 7 String str1="疯狂Java"; 8 String str2=s1+s2; 9 System.out.println(str1==str2); 10 System.out.println(str1.equals(str2)); 11 } 12 } 13 ---------- 运行Java捕获输出窗 ---------- 14 false 15 true 16 17 输出完成 (耗时 0 秒) - 正常终止
上述示意图:
从上面可以看出str1,str2虽然存储内容相同,但是指向的不同的内存空间。
str1==str2;输出结果为false
由于String类已经重写了equals()方法,只要字符串包含的字符序列相同,通过equals()比较就放会true。
str1.equals(str2);输出为true。
按照Object类提供的equals()方法,两个对象相同相等必须指向同一块内存空间。在大多数时候,我们需要判断两个对象是否相等,只要关键成员变量相等并属于同一个类的实例变量。所以我们需要重写equals()方法,以适用对象比较。
1 class Apple 2 { 3 private String color; 4 private double weight; 5 6 public Apple(String color,double weight) 7 { 8 this.color=color; 9 this.weight=weight; 10 } 11 @Override 12 public boolean equals(Object obj) 13 { 14 if(this==obj) 15 return true; 16 else if(obj!=null&&obj.getClass()==Apple.class) 17 { 18 var AppleObj=(Apple)obj; 19 if(this.color==AppleObj.color&&this.weight==AppleObj.weight) 20 { 21 return true; 22 } 23 else 24 return false; 25 } 26 else 27 return false; 28 } 29 } 30 public class OverrideEquals 31 { 32 33 public static void main(String[] args) 34 { 35 var ap1=new Apple("red",2.5); 36 var ap2=new Apple("red",2.5); 37 var ap3=new Apple("red",2.0); 38 39 //未重写equals()方法 40 //System.out.println(ap1.equals(ap2));//输出false 41 System.out.println(ap1.equals(ap2));//true 42 System.out.println(ap1.equals(ap3));//false 43 44 } 45 }