Как напечатать адрес объекта, если вы переопределили метод toString

Я новичок в Java. Сейчас я изучаю equals и == и переопределение equals и toString.

Я хотел бы использовать метод toString, который я переопределил, и метод по умолчанию, унаследованный от класса Object.

Я не смог использовать этот супер модификатор, чтобы достичь этого метода.

Это только для образовательных целей. То, что я хотел бы получить, станет более понятным, если вы посмотрите комментарии в моем коде.

Не могли бы вы помочь мне здесь?

Мой код:

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 + "]";
    }

}

5 ответов

Решение

Строго говоря, вы не можете напечатать адрес объекта в чистом Java. Число, которое выглядит как адрес объекта в строке, созданной Object.toString() это хеш-код объекта. Это может или не может быть связано с текущим адресом объекта:

  • В спецификациях не указано, как рассчитывается номер хеш-кода идентификатора. Это намеренно оставлено неуказанным.

  • Поскольку номер является хеш-кодом, он не может измениться. Таким образом, даже если он (как правило) связан с адресом объекта, это будет адрес объекта в момент первого обращения к хеш-коду. Это может отличаться от его текущего адреса, и оно будет другим, если GC переместил объект с момента первого наблюдения хеш-кода идентификатора объекта.

  • На 64-битной JVM (с достаточно большим размером кучи / без использования сжатых операций) адреса не будут вписываться в идентификационный номер хеш-кода, который возвращается как int,

Во всяком случае, способ получить этот номер - позвонить System.identityHashCode(obj),


Если вам действительно нужен текущий адрес объекта, вы можете получить его с помощью JNI и нативного метода (и некоторого нарушения абстракции) или с помощью методов в Unsafe учебный класс. Но имейте в виду, что оба эти подхода непереносимы... и что адреса объектов, которые они вам дают, могут "сломаться" при запуске GC.


Для сомневающихся, это то, что Java 10 Javadocs говорит о точке "hashcode!= Address":

"(HashCode может или не может быть реализован как некоторая функция адреса памяти объекта в некоторый момент времени.)"

Акцент добавлен. Действительно, с недавними JVM поведение по умолчанию НЕ основывает hashCode на адресе памяти вообще. Так было по крайней мере с Java 7.

Вы можете подтвердить это, включив -XX:+PrintFlagsFinal чтобы выяснить, что hashcode флаг по умолчанию, а затем, глядя на исходный код OpenJDK, чтобы увидеть, что это значит. (Код находится в файле "vm/runtime/synchronizer.cpp" в некоторых версиях, но YMMV.)

Если вы хотите добиться сортировки по умолчанию toString() поведение, вы можете использовать System.identityHashCode() метод. По умолчанию toString() будет выглядеть так:

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

Вы можете вызвать метод super(), чтобы выполнить соответствующий метод суперкласса.

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

toString () в классе объекта выглядит следующим образом

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

Вы можете создать другой метод внутри вашего класса Employee, чтобы использовать супер метод 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);
    }
}

Вот подробный ответ о переопределении equals и хэш-кода

Какие проблемы следует учитывать при переопределении equals и hashCode в Java?

Ключевым моментом является связь между двумя методами:

Всякий раз, когда a.equals(b), тогда a.hashCode() должен быть таким же, как b.hashCode().

Другие вопросы по тегам