在Java中,所有类都直接或间接的继承自 Object
类,Object
类是所有Java类的根基类。这也就意味着所有的Java对象都拥有 Object
类的属性和方法。如果在类的声明中未使用 extends
关键字指明其父类,则默认继承 Object
类。
public class Person /*extends Object*/
toString()方法
查阅API文档可以看到以上关于toString()方法的定义。
首先前半段是 getClass().getName()
,这部分表示的是包名+类名,例如:
package com.test;
public class Test {
public void test(){
System.out.println("This is a test");
}
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.getClass().getName()); // com.test.Test
}
}
中间的 '@'
就是字符 @
。
后半段是 Integer.toHexString(hashCode())
,这部分首先将对象在堆中的地址进行哈希算法返回一个码,即哈希码。然后对这个哈希码使用 toHexString()
方法,返回一个字符串,这个字符串是一个十六进制的数对应的字符串。
package com.test;
public class Test {
public void test(){
System.out.println("This is a test");
}
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.toString()); // com.test.Test@4554617c
}
}
由此可见 Obeject
类的 toString
方法打印出来的东西可读性并不高。也正是因为这样,API文档才建议所有子类都重写此方法。例如在IDEA中可以使用快捷键 Alt
+ Insert
重写 toString()
方法:
package com.test;
public class Test {
int age;
double height;
String name;
public void test(){
System.out.println("This is a test");
}
@Override
public String toString() {
return "Test{" +
"age=" + age +
", height=" + height +
", name='" + name + '\'' +
'}';
}
}
equals()方法
通过下面这个例子来理解 equals()
方法:
public class Phone {
private String brand; //品牌型号
private double price; //价格
private int year; //出产年份
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "Phone{" +
"brand='" + brand + '\'' +
", price=" + price +
", year=" + year +
'}';
}
public Phone() {}
public Phone(String brand, double price, int year) {
this.brand = brand;
this.price = price;
this.year = year;
}
}
public class Test {
public static void main(String[] args) {
Phone p1 = new Phone("华为P40",2035.98,2020);
Phone p2 = new Phone("华为P40",2035.98,2020);
System.out.println(p1==p2); //对于引用数据类型来说,比较的是地址值。所以一定返回的是false
boolean flag = p1.equals(p2); //点进源码发现,底层比较的还是地址值。一定返回的是false,需要重写
System.out.println(flag);
}
}
首先照常编写一个Phone类,并创建两个它的对象,想要比较每个属性是否完全相同。但是对于引用数据类型来说,==
比较的是地址值,p1==p2
返回值一定是 false
。父类 Object
类提供了 equals()
方法比较对象的内容是否相等,但是当我们点进 equals()
方法的源码发现它其实也是用 ==
比较地址值,没有实际意义,还是需要在子类中重写:
// equals()方法的源码
public boolean equals(Object obj) {
return (this == obj);
}
在上面的例子中,重写的代码如下:
public boolean equals(Object obj) { //Object obj = new Phone();
Phone other = (Phone)obj; //将obj转为Phone类型,向下转型,为了获取子类中特有的内容
if(this.getBrand()==other.getBrand()&&this.getPrice()==other.getPrice()&&this.getYear()==other.getYear()){
return true;
}
return false;
}
instanceof
其实上面重写的代码是存在问题的,当传入的对象根本跟 Phone
类没有任何关系时(比如 Cat
类的对象),Phone other = (Phone)obj;
这行代码会产生类型转换错误。所以我们要确保传入的对象是 Phone
类的实例,这时就需要用到 instanceof
运算符。
重写的代码改进如下:
public boolean equals(Object obj) { //Object obj = new Phone();
if(obj instanceof Phone){ //a instanceof b意为判断a对象是否为b这个类的实例
Phone other = (Phone)obj; //将obj转为Phone类型,向下转型,为了获取子类中特有的内容
if(this.getBrand()==other.getBrand()&&this.getPrice()==other.getPrice()&&this.getYear()==other.getYear()){
return true;
}
}
return false;
}
利用IDE快捷重写equals()方法
eclipse
public boolean equals(Object obj){
if(this == obj)
return true; //如果比较的是同一个对象,则返回true
if(obj == null)
return false; //防止传入的参数是null
if(getClass() != obj.getClass())
return false; //防止比较的对象不是同一个类的
Phone other = (Phone)obj;
if(brand == null){
if(other.brand != null)
return false;
} else if(!brand.equals(other.brand))
return false;
if(Double.doubleToLongBits(price) != Double.doubleToLongBits(other.price)) //由于浮点数表示的特性,可能存在精度问题,导致不准确的比较结果,所以用了doubleToLongBits方法
return false;
if(year != other.year)
return false;
return true;
}
IDEA
public boolean equals(Object o) {
if (this == o) return true; //如果比较的是同一个对象,则返回true
if (o == null || getClass() != o.getClass()) return false; //防止传入的参数是null,防止比较的对象不是同一个类的
Phone phone = (Phone) o;
return Double.compare(phone.price, price) == 0 && //同样避免了直接使用==运算符可能引起的浮点数精度问题,如果返回0,表示相等;如果返回正数,表示第一个参数大于第二个参数;如果返回负数,表示第一个参数小于第二个参数。
year == phone.year &&
Objects.equals(brand, phone.brand);
}