views:

510

answers:

3

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?

+4  A: 

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).

Dan Dyer
Here is an exact explanation from Dan Dayer link: The constructor for Inner is protected. However, the constructor is protected relative to Inner, while Inner is protected relative to COne. So, Inner is accessible in CTwo , since it is a subclass of COne. Inner's constructor is not accessible in CTwo, because the class CTwo is not a subclass of Inner! Hence, even though Inner is accessible, its default constructor is not.
mtim
+4  A: 

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");}
    }
}
bruno conde
Yes, correct. .
KLE
A: 

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...
    }
}
wajda
You are not going to be able to create an instance of COne.Inner within CTwo in this way. Making the constructor of COne.Inner protected does two things: 1) it limits the creation of COne.Inner to the other classes in package p1 2) it allows inheritors to call that constructor as part of their construction. Your example is trying to create a new instance of COne.Inner() in another package and just because you are doing that within a class which inherits from COne.Inner doesn't make the constructor accessible. Your constructor will however be called when you create an instance of CTwo.
MikeD