(Редактировать: расширенный ответ, чтобы ответить на некоторые комментарии)
Компилятор берет внутренние классы и превращает их в классы верхнего уровня. Поскольку частные методы доступны только для внутреннего класса, компилятор должен добавить новые «синтетические» методы, которые имеют доступ на уровне пакета, чтобы классы верхнего уровня имели к ним доступ.
Примерно так (знаки $ добавляются компилятором):
class A
{
private void f()
{
final B b;
b = new B();
// call changed by the compiler
b.$g();
}
// method generated by the compiler - visible by classes in the same package
void $f()
{
f();
}
}
class B
{
private void g()
{
final A a;
a = new A();
// call changed by the compiler
a.$f();
}
// method generated by the compiler - visible by classes in the same package
void $g()
{
g();
}
}
Нестатические классы такие же, но в них добавлена ссылка на внешний класс, так что методы могут быть вызваны для него.
Причина, по которой Java делает это таким образом, заключается в том, что они не хотели требовать изменений виртуальной машины для поддержки внутренних классов, поэтому все изменения должны были быть на уровне компилятора.
Компилятор берет внутренний класс и превращает его в класс верхнего уровня (таким образом, на уровне виртуальной машины нет такого понятия, как внутренний класс). Затем компилятор также должен сгенерировать новые методы «пересылки». Они создаются на уровне пакетов (не общедоступных), чтобы гарантировать, что только классы в одном пакете могут получить к ним доступ. Компилятор также обновил вызовы частных методов для сгенерированных методов «пересылки».
Вы можете избежать того, чтобы компилятор генерировал метод, объявляя методы как «пакет» (отсутствие общедоступных, частных и защищенных). Недостатком этого является то, что любой класс в пакете может вызывать методы.
Редактировать:
Да, вы можете вызвать сгенерированный (синтетический) метод, но НЕ ДЕЛАЙТЕ ЭТОГО!:
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Main
{
public static void main(final String[] argv)
throws Exception
{
final Class<?> clazz;
clazz = Class.forName("NotPrivate$A");
for(final Method method : clazz.getDeclaredMethods())
{
if(method.isSynthetic())
{
final Constructor constructor;
final Object instance;
constructor = clazz.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
instance = constructor.newInstance();
method.setAccessible(true);
method.invoke(null, instance);
}
}
}
}
person
TofuBeer
schedule
19.03.2009