Я играл с ASM , и я считаю, что мне удалось добавить модификатор final к полю экземпляра класса; однако затем я приступил к созданию экземпляра указанного класса и вызвал для него сеттер, который успешно изменил значение поля now-final. что-то не так с моим изменением байт-кода, или это принудительно выполняется только компилятором Java?
Обновление: (31 июля) Вот вам код. Основными частями являются
private int x
и private final int y
, Другими словами, мы начинаем с класса с одним финалом (x) и одно незавершенное (y) поле. Делаем x финальным. Мы делаем setX () set y в дополнение к настройке x. Мы бегаем. Оба x и y устанавливаются без ошибок. Код находится на github . Вы можете клонировать его с помощью:
git clone git://github.com/zzantozz/testbed.git tmp
cd tmp/asm-playground
Обратите внимание на два момента: Причина, по которой я задал этот вопрос в первую очередь: и поле, которое я сделал окончательным, и поле, которое уже было окончательным, могут быть установлены с тем, что я считаются обычными инструкциями по байт-коду.
Другое обновление: (1 августа) Протестировано с 1.6.0_26-b03 и 1.7.0-b147 с теми же результатами. То есть JVM с радостью изменяет поля final во время выполнения.
Окончательное (?) Обновление: (19 сентября) Я удаляю полный исходный код из этого сообщения, потому что он был довольно длинным, но он все еще доступен на github (см. Выше).
Я считаю, что окончательно доказал , что JDK7 JVM нарушает спецификацию . (См. отрывок из ответа Стивена .) После использования ASM для изменения байт-кода, как описано ранее, я записал его обратно в файл класса. Используя превосходный JD-GUI , этот файл класса декомпилируется до следующего кода:
package rds.asm;
import java.io.PrintStream;
public class TestPojo
{
private final int x;
private final int y;
public TestPojo(int x)
{
this.x = x;
this.y = 1;
}
public int getX() {
return this.x;
}
public void setX(int x) {
System.out.println("Inside setX()");
this.x = x; this.y = x;
}
public String toString()
{
return "TestPojo{x=" +
this.x +
", y=" + this.y +
'}';
}
public static void main(String[] args) {
TestPojo pojo = new TestPojo(10);
System.out.println(pojo);
pojo.setX(42);
System.out.println(pojo);
}
}
Краткий взгляд на него должен сказать вам, что класс никогда не будет компилироваться из-за переназначения последнего поля, но все же запуск этого класса на простом ванильном языке JDK 6 или 7 выглядит так:
$ java rds.asm.TestPojo
TestPojo{x=10, y=1}
Inside setX()
TestPojo{x=42, y=42}