В исходном коде JDK для java.lang.String.toCharArray он не использует Arrays.copyOf для реализации этого и говорит:
Cannot use Arrays.copyOf because of class initialization order issues
В чем заключаются «проблемы с порядком инициализации класса»?
public char[] toCharArray() {
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;
}
@AsfK Я предполагаю, что OP принимает часть исходного кода JDK. (не MCVE?)
Честно говоря, без серьезного анализа @BrianGoetz мог бы быть единственным человеком, который мог бы ответить.
@Asfk Я думаю, что Arrays.copyOf означает использование Arrays.copyOf(value , value.length) для реализации.
@shaoyihe, ты прав, я ошибся. Я не знаком с этим методом, но когда я меняю значение на char [], он работает, возможно, возникает проблема несоответствия типов ..




Я сделал тест по этому поводу. Ниже приведены работы, которые я сделал:
String.java от JDK.Измените его метод toCharArray, чтобы использовать Arrays.copyOf.
как это:
public char[] toCharArray() {
// Cannot use Arrays.copyOf because of class initialization order issues
/*char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;*/
return Arrays.copyOf(value, value.length);
}
скомпилируйте этот модифицированный String и сохраните его обратно в файл JRE rt.jar.
Напишите простой Java-код HelloWorld.
Скомпилируйте и запустите код с помощью программы java.
И наконец, я получаю вот что:
PS D:\> & 'C:\Program Files (x86)\Java\jdk1.8.0_121\jre\bin\java.exe' StringTest
Error occurred during initialization of VM
java.lang.NullPointerException
at java.util.Hashtable.remove(Hashtable.java:491)
at java.lang.System.initProperties(Native Method)
at java.lang.System.initializeSystemClass(System.java:1166)
Мы видим, что это действительно ошибка initialization. И поскольку System.initProperties - это нативный метод, я не могу проверить его код.
Однако мы можем догадаться, почему это могло произойти:
System.initProperties должен обрабатывать некоторые строки при инициализации свойств системы.String.toCharArray для получения массивов символов из этих строк.Arrays.copyOf, но в этот момент и на этот раз Arrays не был загружен / инициализирован.class initializing request (я не уверен в этом, сообщите мне, если я ошибаюсь !!), и это приведет к NullPointerException и завершению работы виртуальной машины.2018.04.10 Обновление.
Хочу поблагодарить @Radiodef за подсказку. Но когда я попытался войти в коды C++, меня остановило так много путей выполнения, с которыми я не мог справиться без запуска или отладки JVM OpenJDK.
А потом я изменил свою стратегию. Я сделал еще несколько тестов на основе вышеизложенного, которые я делал в течение нескольких дней.
На этот раз я не собираюсь использовать Arrays.copyOf с String.toCharArray, вместо этого я пытаюсь выяснить, какие коды будут вызывать метод toCharArray при инициализации JVM.
Итак, я модифицирую String, добавляя к нему две статические переменные:
public static int count;
public static Throwable[] logs = new Throwable[10000];
В котором count используется для подсчета вызовов toCharArray, logs используется для хранения трассировки стека этих вызовов.
В методе toCharArray:
public char[] toCharArray() {
if (count < logs.length) {
try {
throw new RuntimeException();
} catch (Throwable e) {
logs[count] = e;
}
}
count++;
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;
}
После этого я снова компилирую String и сохраняю его обратно в rt.jar.
Затем я пишу тестовую программу для печати count и трассировки стека вызовов:
Class<String> clazz = String.class;
Field count = clazz.getDeclaredField("count");
System.out.println(count.getInt(null));
Field logs = clazz.getDeclaredField("logs");
Throwable[] arr = (Throwable[]) logs.get(null);
for (Throwable e : arr) {
if (e != null)
e.printStackTrace(System.out);
}
Мы не можем получить доступ к String.count & String.logs непосредственно в наших кодах, поскольку компилятор (javac) не распознает эти поля и вызовет ошибку компиляции. Вот почему я использую для этого рефлексию.
Запустите программу, которую мы только что написали, и результат будет:
525
java.lang.RuntimeException
at java.lang.String.toCharArray(String.java:2889)
at sun.nio.cs.ext.GBK.initb2c(Unknown Source)
at sun.nio.cs.ext.GBK.newDecoder(Unknown Source)
at java.lang.StringCoding$StringDecoder.<init>(Unknown Source)
at java.lang.StringCoding$StringDecoder.<init>(Unknown Source)
at java.lang.StringCoding.decode(Unknown Source)
at java.lang.String.<init>(String.java:414)
at java.lang.String.<init>(String.java:479)
at java.lang.System.initProperties(Native Method)
at java.lang.System.initializeSystemClass(Unknown Source)
......
java.lang.RuntimeException
at java.lang.String.toCharArray(String.java:2889)
at sun.net.www.ParseUtil.encodePath(Unknown Source)
at sun.misc.URLClassPath$FileLoader.getResource(Unknown Source)
at sun.misc.URLClassPath.getResource(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
Какой длинный список призывов. Однако он более ясен, чем предыдущий тест. Мы ясно видим, какие классы вызывают toCharArray.
Hashtable строка 491 предполагает, что ключ, который является null, каким-то образом передается методу Properties.remove.
где инициализировать
value? вы используете конструктор копирования? см. i-programmer.info/programmer-puzzles/168-c/…