Как возражает.toString () получает "адрес памяти" и как я могу его имитировать
на toString
метод Object
уникален тем, что он кажется единственным местом в Java, где адрес памяти доступен для просмотра. Как это Object
этого?
Я хотел бы знать, чтобы я мог имитировать его реализацию в своем собственном классе. Я не могу использовать super.toString()
потому что я расширяю класс, который переопределяет toString
уже.
Update: предпосылка моего вопроса запрашивает адрес памяти, но ответы указали, что эта предпосылка неверна, поэтому на самом деле я спрашиваю: как Object.toString()
Возвращение, что он делает, и как я могу имитировать это?
5 ответов
это не адрес памяти, это hashCode()
. См. также Object.toString()
который говорит (частично)
The
toString
метод классаObject
возвращает строку, состоящую из имени класса, экземпляром которого является объект, символа at-sign@
, и беззнаковое шестнадцатеричное представление хэш-кода объекта. Другими словами, этот метод возвращает строку, равную стоимости:getClass().getName() + '@' + Integer.toHexString(hashCode())
и Object.hashCode()
говорит (это обычно реализуется путем преобразования внутренний адрес объекта в целое число, но этот метод реализации не требуется язык программирования Java™.) так это не требуются быть адресом памяти, и если он используется, он виден только для внутренней (родной) реализации Object
.
метод toString объекта уникален тем, что он кажется единственным местом в Java, где адрес памяти доступен для просмотра. Как объект делает это?
он не получает адрес, в HotSpot JVM он получает случайно сгенерированный 31-битный хэш-код, хранящийся в заголовке объекта. Это должно быть сохранено, потому что;
- хэш-код не может измениться, даже если объект перемещен и имеет новый адрес.
- адрес не достаточно случайно. Младшие 8 бит адреса всегда равен 0. После каждого GC первый объект, который будет создан, всегда один и тот же.
- адрес может быть 64-разрядной.
ПОПРОБУЙТЕ ЭТО ДОМА, НЕ ПОДХОДИТ ДЛЯ РАБОТЫ!!.
вы можете получить/установить hashCode () с помощью Unsafe
static final Unsafe UNSAFE;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
}
public static void setIdentityHashCode(Object o, int code) {
UNSAFE.putInt(o, 1l, code & 0x7FFF_FFF);
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Double d = 1.0;
Double d2 = 1.0;
setIdentityHashCode(d, 1);
setIdentityHashCode(d2, 1);
System.out.println("d: "+d+" System.identityHashCode(d): "+System.identityHashCode(d));
System.out.println("d2: "+d2+" System.identityHashCode(d2): "+System.identityHashCode(d2));
System.out.println("d == d2: " + (d == d2));
}
печать
d: 1.0 System.identityHashCode(d): 1
d2: 1.0 System.identityHashCode(d2): 1
d == d2: false
вы можете получить адрес из опорного значения при условии, что вы знаете, как была переведена память. В простейшем case, (где у вас есть 64-разрядные ссылки) ССЫЛКА непереведена, а адрес-это значение, хранящееся в ссылке.
если вы запустите это на 64-разрядной JVM с -XX:-UseCompressedOops
// This only works if a GC doesn't move the object while attempting to access it.
static final Unsafe UNSAFE;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
}
// run with: -ea -XX:-UseCompressedOops
public static void main(String[] args) {
Object i = 0x12345678;
System.out.printf("indentityHashCode = %08x%n", System.identityHashCode(i));
Object[] obj = { i };
assert Unsafe.ARRAY_OBJECT_INDEX_SCALE == 8; // 8 bytes per reference.
long address = UNSAFE.getLong(obj, (long) Unsafe.ARRAY_OBJECT_BASE_OFFSET);
System.out.printf("%x%n", address);
for (int j=0;j<24;j++)
System.out.printf("%02x ", UNSAFE.getByte(address + j) & 0xFF);
System.out.println();
// now some really scary sh!t
UNSAFE.putLong(i, 8L, UNSAFE.getLong(0L, 8L));
System.out.printf("`i` is now a %s and is %x%n", i.getClass(), i);
}
печать
indentityHashCode = 5a07e868
7fbf41cb8560
01 68 e8 07 5a 00 00 00 48 33 3f b9 b9 7f 00 00 78 56 34 12 00 00 00 00
^^hashCode^ ^class address ^ ^int value^
`i` is now a class java.lang.Long and is 12345678
это не так. Он получает хэш-код, а не адрес памяти, и хэш-код не имеет необходимого соединения с адресом памяти. (Это может быть в некоторые реализаций.)
в базовой реализации, то есть System.identityHashCode
, хотя он по-прежнему не имеет никакого отношения к адресу памяти.
если вы можете найти определение этого toString()
на Object
класса. Вы найдете это.
getClass().getName() + '@' + Integer.toHexString(hashCode()) //returns classname@hashCode.
что это hash-code
, не адрес памяти (согласно Луису Вассерману) , а хэш-код не имеет необходимого соединения с адресом памяти.
вы должны переопределить этот toString()
для каждого класса, который вы объявили в своем проекте в соответствии с вашими потребностями.
Это не лазейка для получения адреса памяти, потому что все, что вы получаете, это случайно сгенерированный 31-битный хэш-код в заголовке объекта. Он не предоставляет никакого реального способа получить реальный адрес памяти.