package com.atguigu.exer3;
class Order{
private int orderId;
private String orderName;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Order(int orderId, String orderName) {
this.orderId = orderId;
this.orderName = orderName;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj instanceof Order) {
Order order = (Order) obj;
return this.orderId == order.orderId &&
this.orderName == order.orderName;
}
return false;
}
}
定义一个Order嘞,有两个私有属性,一个int型,一个string型。而注意,我们重写的equals的类方法中写的是 this.orderName == order.orderName那么按照我之前的理解,这里的orderName是string类型,也就是说应该是引用数据类型,引用数据类型比较的是地址值,那么按照我们的理解,这两个对象的string类型属性orderName的地址值不可能相同,那么下面的测试函数就应该返回false,因为尽管第一个属性orderId是相同的,第二个属性的属性值也是相同的,但是第二个属性比较的是地址值,按照我们的理解,不同对象中的属性地址值肯定不同。但其实是相同的。
public class OrderTest {
public static void main(String[] args) {
Order order1 = new Order(1001, "cc");
Order order2 = new Order(1001, "cc");
System.out.println(order1.equals(order2));
}
}
执行结果明显是true,说明在比较引用数据类型的地址的情况下,二者依旧是相等的。
为什么呢?因为string这个引用数据类型比较特殊,当我们赋予两个order对象的string属性都是同样值得时候,其引用地址都是一样的。如
String A = "cc";
String B = "cc";
注意,尽管这里声明了两个string类型的变量值都是"cc",但是其实在jvm的作用下。A所指向的数据在常量池中,而常量池又在堆中(之前的jdk版本是在方法区中)。而常量池中如果说又新生成了同一类型相同值的数据,那么常量池中不会再新增一个同样的数据,而是将新声明的变量引用指向原来的那个数据。如下图所示,也就是说通过上面的两个语句所生成的string类型数据是生成在常量池当中的,而常量池中的数据又有一个特点就是,上面所说的,当在常量池中生成同样的数据的时候,避免空间的浪费,会将多个引用指向同一内存空间,即同一数据。
因此!!!这就是为什么我们上面的代码,明明比较的是地址值,明明比较的是不同对象中同一属性的地址值,却依然能搞得到相同的原因。因为两个string类型属性的地址值是相同的,即在构造器构造Order对象时,用的语法是!this.orderName = orderName,跟我们上面举例的例子一样。所以当两个构造器都在用这个语句生成,就会出现上面的相似结果!地址是一致的,那么我们如果把类型中属性的构造语句换成这个呢
public Order(int orderId, String orderName) {
this.orderId = orderId;
this.orderName = new String(orderName);
}
得到的运行结果如下
当然是false了,因为地址值是不同的,所以自然而然就是false。所以上述的equals代码并没有真正的实现我们想要的equals。因为其两个属性都是1001和"cc"。因为我们的equals方法是错误的,string类型也有string类型重写好的equals方法,因此我们应该将上面的重写的equals方法改为正确的方法。
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj instanceof Order) {
Order order = (Order) obj;
return this.orderId == order.orderId &&
this.orderName.equals(order.orderName);
}
return false;
}
在这种代码下,就基本上不会存在上面的大多数问题,包括在常量池中造成的相同地址值。所以还是要注意细节。万一写成了==去比较string类型的相同与否,可能会带来很多问题。