Доступ к закрытому внутреннему классу в одном пакете

У меня есть две единицы компиляции:

public class OuterClass{

    private static class InnerClass{

        public String test(){
            return "testing123";
        }
    }

    public static void main( String[] args ){
        new CallingClass().test( new InnerClass() );
    }
}


public class CallingClass{

    public void test( Object o ){
        try{
            Method m = o.getClass().getMethod( "test" );
            Object response = m.invoke( o );
            System.out.println( "response: " + response );
        }
        catch( Exception e ){
            e.printStackTrace();
        }
    }
}

Если они находятся в одном пакете, все работает и печатается "response: testing123". Если они находятся в отдельных пакетах, выбрасывается исключение IllegalAccessException.

Как я понимаю, исключение вызывается, потому что CallingClass не может вызывать частные методы InnerClass. Но я не понимаю, почему это разрешено в одном пакете? InnerClass не защищен пакетом. Частный не должен быть видимым вне OuterClass, даже если он находится в одном пакете. Я понимаю что-то не так?

Ответ 1

javap подпись для внутреннего класса:

class modifiers.OuterClass$InnerClass extends java.lang.Object{
    final modifiers.OuterClass this$0;
    public java.lang.String test();
}

Когда дело доходит до байт-кода (т.е. время выполнения), нет такой вещи, как частный класс. Это выдумка, поддерживаемая компилятором. В API отражения есть доступный для пакета тип с общедоступным методом-членом.

Действительные модификаторы доступа определены в спецификации JVM:

Flag Name      Value   Interpretation
ACC_PUBLIC     0x0001  Declared public; may be accessed from outside its package.
ACC_FINAL      0x0010  Declared final; no subclasses allowed.
ACC_SUPER      0x0020  Treat superclass methods specially when invoked by the
                       invokespecial instruction.
ACC_INTERFACE  0x0200  Is an interface, not a class.
ACC_ABSTRACT   0x0400  Declared abstract; may not be instantiated. 

Ответ 2

Частный модификатор доступа сильнее, чем один пакет (т.е. вообще не имеет модификатора доступа на Java). Следовательно, частные элементы класса - будь то поля, методы или внутренние классы - доступны только внутри этого класса.