Protected inner classes and inheritance

S

Scott Harper

Apologies if I am missing something obvious, but here's the situation. I have
a top-level class with a protected inner class. I have a second-level class
in a different package that extends the top-level class. For example:

package somePackage;

public class TopLevel
{
protected class Inner
{
protected int intField = 0;

protected Inner()
{
// constructor
}

protected void innerMethod()
{
return;
}
}
}


package somePackage.otherPackage;

import somePackage.TopLevel;
import somePackage.TopLevel.Inner;

public class SecondLevel extends TopLevel
{
public SecondLevel()
{
// constructor
}

public void someMethod()
{
Inner inner = new Inner();

inner.intField = 1;

inner.innerMethod();
}
}


When I compile the second class, I get at least 4 errors:

The type somePackage.TopLevel.Inner is not visible
The constructor TopLevel.Inner() is not visible
The field TopLevel.Inner.intField is not visible
The method innerMethod() from the type TopLevel.Inner is not visible

I thought I read the Java docuementation clearly when is says

"The protected modifier specifies that the member can only be accessed within
its own package (as with package-private) and, in addition, by a subclass of
its class in another package."

and

"You can use the same modifiers for inner classes that you use for other
members of the outer class. For example, you can use the access specifiers --
private, public, and protected -- to restrict access to inner classes, just as
you do to other class members."

If I simply make TopLevel.Inner a public class, the errors go away. But I
don't really want to do that... Anything obvious??


thanks
scott
 
S

Scott Harper

If I simply make TopLevel.Inner a public class, the errors go away. But I
don't really want to do that...

Check that... I have to make *everything* in the Inner class public to
resolve all the errors. And by doing that I no longer need to import the
Inner class either...


scott
 
S

Scott Harper

Check that... I have to make *everything* in the Inner class public to
resolve all the errors. And by doing that I no longer need to import the
Inner class either...

Also, if I move the SecondLevel class into the package somePackage, I can keep
the Inner class and its members protected.
 
V

visionset

Scott Harper said:
Check that... I have to make *everything* in the Inner class public to
resolve all the errors. And by doing that I no longer need to import the
Inner class either...

Inner is only accessible to members of the same package or any subclass.
You are not in the same package and you have no subclass of Inner.
 
L

Lew

visionset said:
Inner is only accessible to members of the same package or any subclass.
You are not in the same package and you have no subclass of Inner.

What about
public class SecondLevel extends TopLevel
from the original post?

I, too, am surprised that Inner (not its members, but the class itself) would
not be accessible from a subclass.

-- Lew
 
V

visionset

Lew said:
What about
from the original post?

I don't see that is relevant.
However, when I made the inner class subclass TopLevel.Inner it didn't help,
and so now I'm suprised too.
I couldn't find anyhing in the JSL that made explicit mention to this. Only
the phrase 'not all modifiers apply to all declarations' or some such. I'm
aware of this and that the compiler silently ignores superfluous key-wordage
all over the place eg public in interface methods.
 
D

Daniel Pitts

Also, if I move the SecondLevel class into the package somePackage, I can keep
the Inner class and its members protected.

Actually, I think the problem is with your import statements:
Change them to:
import somePackage.TopLevel;
//import somePackage.TopLevel.Inner; Or delete this...

and try again.
 
P

Piotr Kobzda

Daniel Pitts wrote:

[...]
Actually, I think the problem is with your import statements:
Change them to:
import somePackage.TopLevel;
//import somePackage.TopLevel.Inner; Or delete this...

It makes an Inner class accessible from SecondLevel. However, it's
strange a bit that the compiler checks an access to classes on import
statement level... it shouldn't (IMO) !

Anyway, previously inaccessible members of TopLevel.Inner class now
might be accessed that way:

public class SecondLevel extends TopLevel {
protected /* or private */ class Inner extends TopLevel.Inner {
// all protected members of TopLevel.Inner are accessible
here...


piotr
 
S

Scott Harper

Actually, I think the problem is with your import statements:
Change them to:
import somePackage.TopLevel;
//import somePackage.TopLevel.Inner; Or delete this...

and try again.

no, that doesn't solve it...


scott
 
D

Daniel Pitts

Actually, I think the problem is with your import statements:
Change them to:
import somePackage.TopLevel;
//import somePackage.TopLevel.Inner; Or delete this...
and try again.

no, that doesn't solve it...

scott[/QUOTE]

Hmm..
You're right. However, if you make everything public, you can keep
Inner protected.

This make sense to me in a way.

Inner's members are protected from anyone who doesn't inherit from
Inner. The only inconsistency here is that outer classes can reference
inner classes members, regardless of access modifier. Inner itself
isn't inherited into SecondLevel, only the namespace of the definition
is.
 
S

Scott Harper

Hmm..
You're right. However, if you make everything public, you can keep
Inner protected.

This make sense to me in a way.

Inner's members are protected from anyone who doesn't inherit from
Inner. The only inconsistency here is that outer classes can reference
inner classes members, regardless of access modifier. Inner itself
isn't inherited into SecondLevel, only the namespace of the definition
is.

Ah ha, I hadn't tried that particular permutation, but right you are...

So, I'm not inheriting from Inner, I'm inheriting from TopLevel, which has
Inner as a (protected) member. I guess by making Inner itself protected, only
my inherited class (SecondLevel) has access to it (outside of Inner's
package). And then, because Inner's members are all public, once I can
"see" the class, I have access to the public members.

Any other class that didn't inherit from TopLevel wouldn't be able to
reference Inner anyway, so it doesn't matter if its members are public or not.

Or is that what you just said? :)

Just for grins, I made Inner private, and sure enough, even though its members
are still public, the inheriting class (SecondLevel) can't resolve them.


thanks
scott
 
L

Lew

Scott said:
Any other class that didn't inherit from TopLevel wouldn't be able to
reference Inner anyway, so it doesn't matter if its members are public or not.

Classes in the same package with TopLevel would see TopLevel's protected
members whether or not they extend TopLevel.

-- Lew
 
P

Piotr Kobzda

Scott said:
no, that doesn't solve it...

It does. Moreover, it solves most important problem. Even when all
Inner's members are public, and both above imports holds, the compiler
complains with:

SecondLevel.java:4: somePackage.TopLevel.Inner has protected access in
somePackage.TopLevel
import somePackage.TopLevel.Inner;
^
1 error


So the above change is required to solve other problems.

After having it solved you can choose from different solutions of
accessing Inner's members (make them public, inherit using own inner
class, and the like...).


However, I don't understand why the compiler prohibits the second
import? Importing something doesn't implies any access violation on its
use, does it?

Is there some reasonable explanation for that prohibition?


piotr
 
P

Piotr Kobzda

Scott Harper wrote:

[...]
Any other class that didn't inherit from TopLevel wouldn't be able to
reference Inner anyway, so it doesn't matter if its members are public or not.

It's safe, if you do not expose any Inner's instance to the other
classes, and Inner constructors are protected (or private). Otherwise,
public members are accessible.

For example, the following will change 'intField' of a given
TopLevel.Inner instance:

Object innerInstance = ...
innerInstance.getClass().getField("intField")
.setInt(innerInstance, 100);

Just for grins, I made Inner private, and sure enough, even though its members
are still public, the inheriting class (SecondLevel) can't resolve them.

Even when class is private, reflective access to its public members is
still allowed -- standard Java security mechanisms (SecuritManager
enabled, etc.) do not prohibit that.

Of course, my first statement from this post still holds here, if you
protect an instance and its class' constructors, you are safe.


piotr
 
P

Piotr Kobzda

Daniel said:
However, if you make everything public, you can keep
Inner protected.
[...]

Inner's members are protected from anyone who doesn't inherit from
Inner.

Not fully protected (see my previous post).
The only inconsistency here is that outer classes can reference
inner classes members, regardless of access modifier. Inner itself
isn't inherited into SecondLevel, only the namespace of the definition
is.

Hmm... I don't get it -- there is no any inconsistency IMHO.

AIUI, the Inner class is a member of TopLevel class, and as a member
(not a ?namespace?) is inherited by/into the SecondLevel class.

The access modifiers of Inner's members are honored the same way as for
any other language element, regardless of the SecondLevel class access
level to the Inner class.

That's how I see that. Am I missing something?


piotr
 
L

Lew

Piotr said:
Daniel said:
However, if you make everything public, you can keep
Inner protected.
[...]

Inner's members are protected from anyone who doesn't inherit from
Inner.

Not fully protected (see my previous post).
The only inconsistency here is that outer classes can reference
inner classes members, regardless of access modifier. Inner itself
isn't inherited into SecondLevel, only the namespace of the definition
is.

Hmm... I don't get it -- there is no any inconsistency IMHO.

AIUI, the Inner class is a member of TopLevel class, and as a member
(not a ?namespace?) is inherited by/into the SecondLevel class.

The access modifiers of Inner's members are honored the same way as for
any other language element, regardless of the SecondLevel class access
level to the Inner class.

That's how I see that. Am I missing something?

It's dicey to articulate Java's rules because sometimes we see it as a
strictly compiled language, and sometimes we explicitly acknowledge its
interpretive and reflective capabilities. I was reading the first part of the
thread in terms of javac only, as stated by the OP, wherein reflection is not
relevant.

Had the topic opened the door to runtime considerations then we'd be in "yeah,
but" territory.

-- Lew
 
P

Piotr Kobzda

Lew said:
Piotr said:
Daniel said:
However, if you make everything public, you can keep
Inner protected.
[...]

Inner's members are protected from anyone who doesn't inherit from
Inner.

Not fully protected (see my previous post).
The only inconsistency here is that outer classes can reference
inner classes members, regardless of access modifier. Inner itself
isn't inherited into SecondLevel, only the namespace of the definition
is.

Hmm... I don't get it -- there is no any inconsistency IMHO.

Ah, I see that now! Daniel is talking about inconsistency with general
access rules between the same level outer and inner classes -- which I
completely agree with (don't mind here, how that access is
implemented!). I, by mistake, tried to apply Daniel's point into the
OP's particular case, taking as outer class the SecondLevel class (not
even sure now, if it's legal to call it outer?). So, that part is clear
now.
It's dicey to articulate Java's rules because sometimes we see it as a
strictly compiled language, and sometimes we explicitly acknowledge its
interpretive and reflective capabilities. I was reading the first part
of the thread in terms of javac only, as stated by the OP, wherein
reflection is not relevant.

Sure. However, I'm not really care about reflection here.
Had the topic opened the door to runtime considerations then we'd be in
"yeah, but" territory.

Oh, not really. My confusion expressed here is Java language level related.

For me, each inner class is _a member_ of the class immediately
enclosing it, and just like other members (i.e. fields, and methods), is
inherited by subclasses of that enclosing class.

Daniel said, that inner class is not inherited, and that's what I'm
trying to argue with.


piotr
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top