20 июн. 2009 г.

Java: Synthetic method

Не смотря на то, что вложенные классы могут обращаться к private свойствам и методам класса, который их содержит - подобное обращение происходит не на прямую, а через так называемый синтетический метод, создаваемый компилятором.
Пример демонстрирующий данное положение:
public class A {
private int i;
public int k;

private class B { 
public B() {
int sum = i + k;
}
}
}

С точки зрения компиляторов - всё хорошо и только eclipse на такой код выдаст предупреждение о синтетическом доступе к свойству i и предложит расширить её область видимости до области видимости по-умолчанию, либо как вариант предложит добавить аннотацию @SuppressWarnings("synthetic-access") дабы больше не умолчать об этом.
Теперь посмотрим какие собственные методы есть у класса A: A.class.getDeclaredMethods() и увидим:
static int A.access$000(A)
Начиная с java 5 java.lang.reflect.Method имеет метод isSynthetic(), который характеризует метод как синтетический и для данного метода он вернёт нам true.
байт-код метода access$000(A):
0 aload_0
1 getfield #1 <A.i>
4 ireturn
так выглядит соответствующий ему java код
static int access$000(A a) {
return a.i;
}

И так выглядит байт-код конструктора класса B:
 0 aload_0
1 aload_1
2 putfield #1 <A$B.this$0>
5 aload_0
6 invokespecial #2 <java/lang/Object.<init>>
9 aload_1
10 invokestatic #3 <A.access$000>
13 aload_1
14 getfield #4 <A.k>
17 iadd
18 istore_2
19 return
т.е другими словами java код конструктора класса B выглядит так:
public B() {
super();
int sum = A.access$000(A.this) + A.this.k;
}


ps. в очередной раз спасибо мудрому товарищу Бассу за совет по дельному инструменту для просмотра байт-кода jclasslib.

6 комментариев:

Alexander Lipatov комментирует...

Спасибо! Я понял, что ничего по этой теме не понял :-) и пошел читать http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.pdf

Владимир Долженко комментирует...

2Alexander Lipatov:
Александр, а причём тут generics (которые есть в java 5+) и синтетические методы, которые было и до java 5 ?
Что именно не понятно ?

Alexander Lipatov комментирует...

Видимо я не в ту сторону копал. Искал "что такое синтетический метод" и наткнулся на ссылку на этот FAQ.

А потом нашел вот это:
"Насколько я отдаленно понимаю, компилятор иногда прибегает к некоторым хитростям для оптимизации кода. Иногда это доходит до того, что он может создать (внедрить) в классе дополнительные поля или методы. Вот их и называют синтетическими. Соответственно рефлекшн имеет возможность определить, является ли метод синтечическим или нет. Я так понимаю, что и дернуть синтчический метод с помощью рефлекшн можно."

Alexander Lipatov комментирует...

А еще меня смутил джавадок(там говорилось про 1.5):

boolean isSynthetic()
Returns true if this member was introduced by the compiler; returns false otherwise.
Since: 1.5

Владимир Долженко комментирует...

@Alexander Lipatov:
здесь вопрос не хитростях оптимизации, а в возможности реализации данной возможности - ведь доступ к private свойствам или методам есть только у данного класса, но надо полагать, что возможность обращаться из вложенных классов появилась изначально уже в java 1.1, и вот чтобы не нарушить контракт private компилятор и добавляет синтетические методы.
И опять же вопрос не в том как это дёрнуть по reflection - по reflection можно запросто достучаться и к private свойствам - а в том, чтобы понимать механизм подобного обращения и какие издержки при этом существуют.

Владимир Долженко комментирует...

@Alexander Lipatov:
только метод isSynthetic появился в java5, и соответствующее значение модификатора тоже, а суть его была и до java5