Изменчивость строки Java - java.lang.NoSuchFieldException: смещение

Я новичок в Java, и я увидел здесь раздел вопросов и ответов с двумя примерами, в которых устранена изменчивость. После тестирования MutableString.java:

import java.lang.reflect.Field; 

public class MutableString {

    public static void main(String[] args) { 
        String s = "Immutable"; 
        String t = "Notreally"; 

        mutate(s, t);
        StdOut.println(t); 

        // strings are interned so this doesn't even print "Immutable" (!)
        StdOut.println("Immutable");
    } 

    // change the first min(|s|, |t|) characters of s to t
    public static void mutate(String s, String t) {
        try {
            Field val = String.class.getDeclaredField("value"); 
            Field off = String.class.getDeclaredField("offset"); 
            val.setAccessible(true); 
            off.setAccessible(true); 
            int offset   = off.getInt(s); 
            char[] value = (char[]) val.get(s); 
            for (int i = 0; i < Math.min(s.length(), t.length()); i++)
                value[offset + i] = t.charAt(i); 
        } 
        catch (Exception e) { e.printStackTrace(); }
    } 

} 

Я получил следующую ошибку:

java.lang.NoSuchFieldException: offset

Любая информация о следующем будет принята с благодарностью:

а) почему я получаю это исключение
б) как проверить, какие поля существуют в классе (в частности, строки Java)

1 ответ

Решение

Отказ от ответственности: эти виды хаков являются интересными уроками в обучении и забавных мелочах. Но они определенно не то, что вы хотите использовать в любом рабочем коде. Это приведет к боли.

По своей природе такой взлом всегда зависит от деталей реализации взломанных классов.

В вашем случае вы, кажется, используете String реализация, которая не имеет offset поле, но использует какой-то другой механизм (или, может быть, просто другое имя!).

Например, я только что рассмотрел класс Oracle Java 7 String, и у него больше нет offset поле (которое использовалось в Java 6 и ранее, чтобы поделиться char[] среди подстрок)! *

Ты можешь использовать Class.getDeclaredFields() чтобы проверить, какие поля эта реализация определяет:

for (Field f : String.class.getDeclaredFields()) {
  System.out.println(f);
}

Для версии этого хака, которая работает с Java 7, вы можете сделать это:

public static void mutate(String s, String t) {
    try {
        Field val = String.class.getDeclaredField("value"); 
        val.setAccessible(true); 
        char[] value = (char[]) val.get(s); 
        for (int i = 0; i < Math.min(s.length(), t.length()); i++)
            value[i] = t.charAt(i); 
    } 
    catch (Exception e) { e.printStackTrace(); }
} 

Конечно, это тоже сломается, если внутренности String изменить снова.

* Вот электронное письмо, в котором говорится об этом изменении, похоже, что обмен char[] привести к улучшению производительности только в нескольких особых случаях.

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