关于多态中可能出现equals细节问题———String类型变量赋予常量的时候,其地址位置及常量池相关知识

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,说明在比较引用数据类型的地址的情况下,二者依旧是相等的。执行结果明显是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类型的相同与否,可能会带来很多问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值