对象内容在方法中被修改,但对象哈希码保持不变



在这段代码中,我将一个名称传递给一个方法,该方法修改字符串文字name,而不是对象本身,当代码退出该方法时,对象(由哈希码标识)是相同的,但不是在方法中修改的name

我该怎么解释呢?

public class ObjectContentsPassByReferenceApp {
    private static void modifyObject(Bus bus) {
        bus.setName("SBS Transit");
    }
    public static void main(String args[]) {
        Bus bus;
        bus = new Bus();
        bus.setName("Trans Island Bus");
        System.out.println("Bus initially set to (hashcode): " + bus);
        System.out.println("Bus name: " + bus.getName());
        modifyObject(bus);
        System.out.println("After calling modifyObject (hashcode): " + bus);
        System.out.println("Bus name: " + bus.getName());
    }
}
class Bus {
    private String name;
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

运行结果:

Bus initially set to (hashcode): sg.java.concepts.passByReference.Bus@8d2ed0
Bus name: Trans Island Bus
After calling modifyObject (hashcode): sg.java.concepts.passByReference.Bus@8d2ed0
Bus name: SBS Transit

您没有覆盖hashCode -因此它将使用java.lang.Object中的实现,其中在对象的生命周期中不会变化。你也没有覆盖equals…这意味着只有当ab引用完全相同的对象时,a.equals(b)才会为Bus aBus b返回true,而不是具有相同名称的对象。

请注意,代码中的名称表明Java使用引用传递。它不会——它总是使用按值传递,但这些值总是原语或引用——而不是实际的对象。对于简单赋值也是如此。

在您的代码中,您正在创建一个单个 Bus对象。把它想象成一辆现实生活中的巴士。它上面有一个名字,上面有一个浮雕的序列号(后者是哈希码)。当您调用该方法时,这是告诉该方法如何获取Bus对象—它不是创建一个新的Bus。该方法使用一个新名称来覆盖名称,但这对序列号没有任何影响,序列号与以前相同。

还要注意name不是字符串字面值——它是字符串变量。它的初始值来自字符串字面值,但稍后更改值对原始字符串对象没有任何影响。

如果你想让哈希码依赖于一个变量(即name),那么你需要覆盖hashCode方法。一个简单的例子:

public class Bus {
    private String name;
    public int hashCode() {
        return name.hashCode();
    }
}

java.lang.Object中的hashCode实现不使用任何类型的反射来查找变量,因此您几乎总是需要重写hashCode

请注意,如果您覆盖hashCode,则应该始终覆盖equals,反之亦然。

有很多有用的工具可以帮助你实现hashCode。查看Apache Commons lang,看看它们的HashCodeBuilder类。

相关内容

最新更新