Can't access protected inner class while inheriting
-
18-09-2019 - |
Question
Reading through "Thinking in Java" i stuck in ex:6 of Inner Classes chapter.
Exercise 6: (2) Create an interface with at least one method, in its own package. Create a class in a separate package. Add a protected inner class that implements the interface. In a third package, inherit from your class and, inside a method, return an object of the protected inner class, upcasting to the interface during the return.
This is my code:
IOne.java
interface
package intfpack;
public interface IOne{
void f();
}
COne.java
Class with protected inner class that implements the interface
package classpack;
import intfpack.*;
public class COne{
protected class Inner implements IOne{
public void f(){System.out.println("Inner class of COne");}
}
}
CTwo.java
Inheriting from class with protected inner class
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();
}
}
Copmiler says next:
javac CTwo.java
CTwo.java:9: Inner() has protected access in classpack.COne.Inner
IOne io = new Inner();
^
1 error
But the book says that i can access protected inner classes in derived class. Where is mistake?
Solution
The error message is complaining about the constructor being protected, not the class. But you haven't explicitly defined a constructor in the code you posted. In this case, according to the JLS, the default constructor will be protected (the same as the class).
OTHER TIPS
You need to define a public
constructor for the Inner
class
:
public class COne {
protected class Inner implements IOne{
public Inner() { }
public void f(){System.out.println("Inner class of COne");}
}
}
That is clear. But here is a really weird thing.
According to the JLS if CTwo extends COne.Inner it is expected to access Inner's protected constructor, but in practice it does not... See below.
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...
}
}
The problem is not about the Inner class but Inheritance.
Let do some experiments.
First Inner
and Outer
class both have full access to each other. So the following code works well.
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!
}
}
Now in another package, DerivedOuter
is derived from Outer
. DerivedOuter
calls inner()
method inherited from Outer
class. It still works!
package com.ciaoshen.packB;
class DerivedOuter extends Outer {
public static void main(String[] args) {
new DerivedOuter().inner().foo(); // Output: Hello Ronald!
}
}
But when I Override the inner()
method in DerivedOuter
class, the same Error occurs!
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
}
}
Conclusion, the protected Inner constructor is only accessible within the original Outer
class scope. Any additional method (ex: your getInner()
method) has no access to protected Inner
constructor.
The key point is that when DerivedOuter
inherit from a Outer
, you can imagine that DerivedClass
IS-A Outer
, and it contains an Inner
class inside as his member. But in fact, DerivedOuter
has no direct access to Inner
class but only works by using his super class Outer
.