如果已重新定义toString方法,如何打印对象的地址

我是Java的新手。 现在我正在研究equals和==以及重新定义equals和toString。

我想使用我已经重新定义的toString方法和从Object类inheritance的默认方法。

我没有使用那个超级修饰符来达到该方法。

这仅用于教育目的。 如果您要查看我的代码中的注释,我希望得到的更清楚。

你能帮帮我吗?

我的代码是:

public class EqualTest{ public static void main(String[] args){ Employee alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15); //System.out.super.println(alice1); Employee alice2 = alice1; //System.out.super.println(alice2); Employee alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15); //System.out.super.println(alice3); System.out.println("alice1==alice2: " + (alice1==alice2)); System.out.println("alice1 == alice3: " + (alice1==alice3)); System.out.println("alice1.equals(alice3): " + alice1.equals(alice3)); } } class Employee{ ... public String toString(){ return getClass().getName() + "[name = " + name + ", salary=" + salary + ", hireDay=" + hireDay + "]"; } } 

严格地说,您无法在纯Java中打印对象的地址。 在Object.toString()生成的String中看起来像对象地址的数字是对象的“身份哈希码”。 它可能与对象的当前地址有关,也可能与之无关:

  • 规范没有说明如何计算身份哈希码编号。 它是故意未指定的。

  • 由于该数字是哈希码,因此无法更改。 因此,即使它(通常)与对象地址相关,也将是首次访问哈希码时的对象地址。 这可能与其当前地址不同,如果GC从第一次观察到对象的标识哈希码以来移动了对象, 则会有所不同。

  • 在64位JVM(具有足够大的堆大小/不使用压缩oops)上,地址将不适合作为int返回的标识哈希码编号。

无论如何,获得此数字的方法是调用System.identityHashCode(obj)


如果你真的想要一个对象的当前地址,你可以使用JNI和本机方法(以及一些抽象破坏)或使用Unsafe类中的方法来获取它。 但要注意这两种方法都是不可移植的……并且当GC运行时,它们给你的对象地址可能会“中断”。


对于怀疑者来说,这就是Java 10 javadocs在“hashcode!= address”点上所说的:

“(hashCode 可能会或可能不会 在某个时间点实现为对象的内存地址的某些function 。)”

强调补充说。 实际上,对于最近的JVM,默认行为是根本不将hashCode基于内存地址。 至少从Java 7开始就是这样。

您可以通过包含-XX:+PrintFlagsFinal来确认这一点,以找出hashcode标志默认的内容,然后查看OpenJDK源代码以了解它的含义。 (代码在某些版本的“vm / runtime / synchronizer.cpp”文件中,但是YMMV。)

如果要实现sort-of default toString()行为,可以使用System.identityHashCode()方法。 默认的toString()将如下所示:

 public String toString(Object o) { return o.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(o)); } 

这是一个关于覆盖equals和hashcode的深入答案

在Java中覆盖equals和hashCode时应该考虑哪些问题?

关键点是两种方法之间的关系是:

每当a.equals(b),则a.hashCode()必须与b.hashCode()相同。

您可以在Employee类中创建另一个方法以使用super toString方法。

见例子:

 public class Employee { public String toString() { return "MyToStringMethod"; } public String superToString() { return super.toString(); } public static void main(String[] args) { Employee b = new Employee(); System.out.println(b); System.out.println(b.superToString()); } } 

或者将两者结合在一起:

 public class Employee { public String toString() { return super.toString() + " MyToStringMethod"; } public static void main(String[] args) { Employee b = new Employee(); System.out.println(b); } } 

您可以调用super()方法来执行相应的超类方法。

 class Employee{ ... public String toString(){ String s = super.toString(); return getClass().getName() + "[name = " + name + ", salary=" + salary + ", hireDay=" + hireDay + "]" + s; } 

Object类中的toString()如下所示

 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }