Ответ 1
Сообщение об ошибке жалуется на защищаемый конструктор, а не на класс. Но вы явно не определили конструктор в коде, который вы опубликовали. В этом случае в соответствии с JLS, конструктор по умолчанию будет защищен (тот же, что и класс).
Чтение через "Мышление в Java" я застрял в главе 6 из раздела "Внутренние классы".
Упражнение 6: (2) Создайте интерфейс, по крайней мере, с одним методом в своем собственном пакете. Создать класса в отдельном пакете. Добавьте защищенный внутренний класс, который реализует интерфейс. В третий пакет, наследовать от вашего класса и, внутри метода, вернуть объект защищенный внутренний класс, переход к интерфейсу во время возврата.
Это мой код:
интерфейс
package intfpack;
public interface IOne{
void f();
}
Класс с защищенным внутренним классом, который реализует интерфейс
package classpack;
import intfpack.*;
public class COne{
protected class Inner implements IOne{
public void f(){System.out.println("Inner class of COne");}
}
}
Наследование класса с защищенным внутренним классом
package thirdpack;
import classpack.*;
import intfpack.*;
public class CTwo extends COne{
public IOne getInner(){
IOne io = new Inner();
return io;
}
public static void main(String[] args){
CTwo ct = new CTwo();
ct.getInner();
}
}
Скотт говорит следующее:
javac CTwo.java
CTwo.java:9: Inner() has protected access in classpack.COne.Inner
IOne io = new Inner();
^
1 error
Но в книге говорится, что я могу получить доступ к защищенным внутренним классам в производном классе. Где ошибка?
Сообщение об ошибке жалуется на защищаемый конструктор, а не на класс. Но вы явно не определили конструктор в коде, который вы опубликовали. В этом случае в соответствии с JLS, конструктор по умолчанию будет защищен (тот же, что и класс).
Вам нужно определить конструктор public
для Inner
class
:
public class COne {
protected class Inner implements IOne{
public Inner() { }
public void f(){System.out.println("Inner class of COne");}
}
}
Это ясно. Но здесь действительно странно.
Согласно JLS, если CTwo расширяет COne.Inner, ожидается, что он получит доступ к внутреннему защищенному конструктору, но на практике это не так., См. Ниже.
package p1;
public class COne {
public static class Inner {
protected Inner() {}
}
}
package p2;
public class CTwo extends COne.Inner {
public void getIface() {
new COne.Inner();
// Compile time error anyway with the same complains:
// "Inner() has protected access in p1.COne.Inner"
// ...unlike my expectations...
}
}
Проблема не в классе Inner, а в Inheritance.
Сделайте несколько экспериментов.
Первый класс Inner
и Outer
имеют как полный доступ друг к другу. Таким образом, следующий код работает хорошо.
package com.ciaoshen.packA;
public class Outer {
protected class Inner {
public void foo() { System.out.println("Hello Ronald!"); }
}
protected Inner inner() {
return new Inner();
}
public static void main(String[] args) {
new Outer().inner().foo(); // Output: Hello Ronald!
}
}
Теперь в другом пакете DerivedOuter
выводится из Outer
. DerivedOuter
вызывает метод inner()
, унаследованный от класса Outer
. Он по-прежнему работает!
package com.ciaoshen.packB;
class DerivedOuter extends Outer {
public static void main(String[] args) {
new DerivedOuter().inner().foo(); // Output: Hello Ronald!
}
}
Но , когда я переопределяю метод inner()
в классе DerivedOuter
, возникает такая же ошибка!
package com.ciaoshen.packB;
class DerivedOuter extends Outer {
@Override
public Inner inner() { // this is not the inner() of Outer class. BOOM!
return new Inner();
}
public static void main(String[] args) {
new DerivedOuter().inner().foo(); // ERROR: Outer.Inner() has protected access in Outer.Inner
}
}
Заключение, защищенный встроенный конструктор доступен только в пределах исходного класса Outer
. Любой дополнительный метод (например: ваш метод getInner()
) не имеет доступа к защищенному конструктору Inner
.
Ключевым моментом является то, что, когда DerivedOuter
наследует от Outer
, вы можете представить, что DerivedClass
IS-A Outer
, и он содержит класс Inner
внутри как его член. Но на самом деле DerivedOuter
не имеет прямого доступа к классу Inner
, но работает только с помощью своего суперкласса Outer
.