Ответ 1
Этот исходный код открывает некоторые интересные методы Java. Давайте рассмотрим один за другим.
Сначала нам нужно понять поток кода. Какая часть кода будет выполнена в первую очередь?
Статический блок инициализации. Зачем? Проконсультируйтесь с Спецификация языка Java (12.4):
Инициализация класса состоит в выполнении его статических инициализаторов и инициализаторов для статических полей (переменных класса), объявленных в классе.
И когда это происходит? Снова из JLS (12.4.1):
T - класс, и статический метод, объявленный T, вызывается.
Итак, мы можем прийти к выводу, что статический initiazlier будет выполняться первым перед основным методом.
Теперь эти две строки используют отражение:
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
Для простоты мы можем разбить первую строку на две строки:
Class<String> c = String.class;
Field value = c.getDeclaredField("value");
Первая строка возвращает Reflected Class Object, а вторая строка возвращает Field
, которая представляет поле value
класс String
.
value.setAccessible(true)
указывает, что объект отраженного класса должен подавлять проверку доступа к языку Java, когда он используется. (Ссылка).
Следующая строка под вопросом
value.set("Hello World", value.get("G'Day Mate."));
Если мы погрузимся в . set() documenation, мы увидим, что мы вызываем set(Object aObject,Object value)
версию set
. value.get("G'Day Mate.")
возвращает значение поля "G'Day Mate."
value
, которое на самом деле является char[]
. И с вызовом set
он заменяет значение поля значения объекта "Hello World"
полем значений объекта "G'Day Mate."
.
Объясняется блок-код static
.
Позволяет погрузиться в основной функционал.
Это довольно просто. Он должен выводить Hello, world
. Но он выводит G'Day Mate
. Зачем?
Поскольку объект Hello, world
String, который мы создали в инициализаторе static
, тот же, что и объект Hello, world
, который мы используем в основной функции. Консультирование с JLS снова проливает свет на него
Кроме того, строковый литерал всегда ссылается на тот же экземпляр класса String. Это связано с тем, что строковые литералы, или, в более общем смысле, строки, которые являются значениями константных выражений (§15.28), "интернированы", чтобы обмениваться уникальными экземплярами, используя метод String.intern.
Этот ответ может помочь вам понять факт более кратко.
Таким образом, он показывает другое значение, поскольку мы уже изменили значение объекта Hello,world
на G'Day, Mate
.
Но если вы используете new String("Hello world")
в основной функции, он будет непосредственно создавать новый экземпляр String
, а не проверять его пул. Таким образом, Hello world
основной функции будет отличаться от Hello world
статического инициализатора, из которого мы изменили значение.