Question on member accessibility

A

ankur

package Pack1;

public class SuperA {
public int supervarA;
protected void superMethA()
{

System.out.println("Package Pack 1 Class SuperA");
}
}


package Pack2;
import Pack1.SuperA;

public class SubB extends SuperA {

SubB varB = new SubB();
SuperA varA = new SuperA();

void subMethB()
{
varB.superMethA();
varB.supervarA = 100;
superMethA();
supervarA = 90;

varA.superMethA(); // (4)Why this does not work
}



}

Why (4) does not work ? I could not understand ( appreciate) the
reason why this access is denied !

Thanks,
Ankur
 
A

ankur

[...]
Why (4) does not work ? I could not understand ( appreciate) the
reason why this access is denied !

When you ask "why", are you simply asking for the rule?  Or why the rule  
exists?

The rule is simple: the "protected" access allows code in a sub-class to  
access base class members, but only via an instance of the sub-class from  
within which the member is being accessed (that is, from a known instance  
of that actual sub-class).  The variable "varA" is not known to be an  
instance of the sub-class "SubB" (and in fact in this case doesn't refer  
to one), and so code within "SubB" does not have access to protected  
members referenced by that variable.
 
A

ankur

[...]
The rule is simple: the "protected" access allows code in a sub-class  
to  
access base class members, but only via an instance of the sub-class  
from  
within which the member is being accessed (that is, from a known  
instance  
of that actual sub-class).  The variable "varA" is not known to be an  
instance of the sub-class "SubB" (and in fact in this case doesn't  
refer  
to one), and so code within "SubB" does not have access to protected  
members referenced by that variable.
But you see in my example above subMethB() was able to directly  
access  superMethA() by name (and not only by an instance of its type  
as varB.superMethA(); )

The instance is implicit.  You could just as easily have written  
"this.superMethA();" with exactly the same meaning to the compiler.

The variable itself isn't so important as what the compiler knows about  
the type of the instance being used to call the method.  The method  
"subMethB()" is an instance member of "SubB", and so calls to other  
instance methods implicitly use the same instance used to call the method  
"subMethB()".  So it's safe to call protected instance members directly  
 from within "subMethB()" as well, as long as they are using the implicit  
"this" reference rather than some other reference not known to be of type  
"SubB".

Pete

Oh yes Pete! , thanks so much for your answer !
 
A

ankur

[...]
Why (4) does not work ? I could not understand ( appreciate) the
reason why this access is denied !

When you ask "why", are you simply asking for the rule?  Or why the rule  
exists?

The rule is simple: the "protected" access allows code in a sub-class to  
access base class members, but only via an instance of the sub-class from  
within which the member is being accessed (that is, from a known instance  
of that actual sub-class).  The variable "varA" is not known to be an  
instance of the sub-class "SubB" (and in fact in this case doesn't refer  
to one), and so code within "SubB" does not have access to protected  
members referenced by that variable.

I think this statement can be modified to say that " "protected" access allows code in a sub-class ( in some other package) to access..." because if the subclass is in the same package then the protected members of superclass can be accessed via superclass reference which refers to a superclass object.

As for why the rule exists, that gets a bit more speculative on my part,  
since I'm not the one who designed Java or similar languages.  However, I  
think it's a reasonable rule, since the "protected" access is there to  
allow sub-classes better control over _themselves_, not other classes.  
The class "SubB" really should only have permission to touch "protected"  
members for instances of itself.  The alternative does not provide enough  
protection for sub-classes that are otherwise unrelated to "SubB".

For example, imagine how disruptive you could be if you could write a  
JComponent sub-class that could retrieve a Graphics instance used to paint  
_some other_ JComponent sub-class by calling the protected method  
getComponentGraphics().  That method is intended for an instance to use  
internally to get its own Graphics instance, not some other instance's.

Or consider (again in JComponent) the protected method  
requestFocusInWindow().  Again, intended for use for a JComponent instance  
on _its own_ behalf.  Other code could be disruptive by calling some other  
instance's requestFocusInWindow() method (especially if that other  
instance was a sub-class that wasn't even supposed to have the focus).

In fact, people could wind up writing sub-classes of certain classes for  
the sole purpose of messing around with _other_ sub-classes of those  
classes.  That breaks encapsulation in some very important ways, and so  
it's not allowed.

Pete
 
A

ankur

[...]
Why (4) does not work ? I could not understand ( appreciate) the
reason why this access is denied !

When you ask "why", are you simply asking for the rule?  Or why the rule  
exists?

The rule is simple: the "protected" access allows code in a sub-class to  
access base class members, but only via an instance of the sub-class from  
within which the member is being accessed (that is, from a known instance  
of that actual sub-class).  The variable "varA" is not known to be an  
instance of the sub-class "SubB" (and in fact in this case doesn't refer  
to one), and so code within "SubB" does not have access to protected  
members referenced by that variable.

As for why the rule exists, that gets a bit more speculative on my part,  
since I'm not the one who designed Java or similar languages.  However, I  
think it's a reasonable rule, since the "protected" access is there to  
allow sub-classes better control over _themselves_, not other classes.  
The class "SubB" really should only have permission to touch "protected"  
members for instances of itself.  The alternative does not provide enough  
protection for sub-classes that are otherwise unrelated to "SubB".

For example, imagine how disruptive you could be if you could write a  
JComponent sub-class that could retrieve a Graphics instance used to paint  
_some other_ JComponent sub-class by calling the protected method  
getComponentGraphics().  That method is intended for an instance to use  
internally to get its own Graphics instance, not some other instance's.

Or consider (again in JComponent) the protected method  
requestFocusInWindow().  Again, intended for use for a JComponent instance  
on _its own_ behalf.  Other code could be disruptive by calling some other  
instance's requestFocusInWindow() method (especially if that other  
instance was a sub-class that wasn't even supposed to have the focus).

In fact, people could wind up writing sub-classes of certain classes for  
the sole purpose of messing around with _other_ sub-classes of those  
classes.  That breaks encapsulation in some very important ways, and so  
it's not allowed.

Pete


I think the statement in your second para can be modified to say that
" "protected" access allows code in a sub-class ( in some other
package) to access..." because if the subclass is in the same package
then the protected members of superclass can be accessed via
superclass reference which refers to a superclass object.
 
J

Joshua Cranmer

ankur said:
Why (4) does not work ? I could not understand ( appreciate) the
reason why this access is denied !

<Geeky JLS reference>
§6.6.2: A protected member or constructor of an object may be accessed
from outside the package in which it is declared only by code that is
responsible for the implementation of that object.
</Geeky JLS reference>

To be specific:
public class A {
protected int field;
protected void method() {}

protected A() {}
}

class B extends A {
public B() {
super();
this.field = 9;
this.method();
}

/*public static void methodA(A a) {
if (a.field == 0)
a.method();
}*/

public static void methodB(B b) {
if (b.field == 0)
b.method();
}

public void methodC(A a) {
if (this.field == 0)
this.method();

//if (a.field == 0)
// a.method();
}
}
class C {
public void method() {
//A a = new A();
A a = new A() { public void method() {} };
}
}

Classes B and C are in a different package from A. The commented out
lines are lines that won't compile because they do not have right
access. The other lines do have right access.

To briefly summarize: a protected member can only be accessed outside of
the package if the accessor "needs" it to implement (e.g., access to the
constructor) or if the object is of the type of the subclass. Hence the
inability to access a.field but the ability to access b.field or this.field.

I don't know the entire rationale behind this, but this is my guess. The
purpose of protected, in the inheritance sense, is to say that "this
property is one I wish to expose to people who need to implement me but
not those who wish to merely use me." So, let us form the class:

class Foo {
protected int importantFieldForInternalUse;
}

Since it's internal, we don't want people mucking about with it, but our
subclass needs to use it. But Joe Hacker comes along and says "if only I
change that important field..." Since Foo is created by other stuff and
passed around by methods, he gets a hold of it to his class:

class Evil extends Foo {
public static void manipulateFoo(Foo object) {
// Bwa-ha-ha! I broke it all!
object.importantFieldForInternalUse = 0;
}
}

Obviously, this is really an external use, not the intended internal
use. So by requiring that the object be of the subtype before you can
get to it, you enforce the notion that protected means "for
implementation purposes only."

Hope this brings some light on the situation.
 
A

Arne Vajhøj

ankur said:
public class SuperA {
protected void superMethA()
{

public class SubB extends SuperA {
SubB varB = new SubB();
SuperA varA = new SuperA();
void subMethB()
{
varB.superMethA();

varA.superMethA(); // (4)Why this does not work
}
}

Why (4) does not work ? I could not understand ( appreciate) the
reason why this access is denied !

It has already been explained that it is not allowed per language
rules.

It is not allowed in C# or C++ either.

Why ?

Peter guessed:

# As for why the rule exists, that gets a bit more speculative on my
part, since
# I'm not the one who designed Java or similar languages. However, I
think it's a
# reasonable rule, since the "protected" access is there to allow
sub-classes
# better control over _themselves_, not other classes. The class "SubB"
really
# should only have permission to touch "protected" members for instances of
# itself. The alternative does not provide enough protection for
sub-classes that
# are otherwise unrelated to "SubB".
#
# For example, imagine how disruptive you could be if you could write a
JComponent
# sub-class that could retrieve a Graphics instance used to paint _some
other_
# JComponent sub-class by calling the protected method
getComponentGraphics().
# That method is intended for an instance to use internally to get its own
# Graphics instance, not some other instance's.
#
# Or consider (again in JComponent) the protected method
requestFocusInWindow().
# Again, intended for use for a JComponent instance on _its own_ behalf.
Other
# code could be disruptive by calling some other instance's
requestFocusInWindow()
# method (especially if that other instance was a sub-class that wasn't even
# supposed to have the focus).
#
# In fact, people could wind up writing sub-classes of certain classes
for the
# sole purpose of messing around with _other_ sub-classes of those
classes. That
# breaks encapsulation in some very important ways, and so it's not allowed.

Joshua guessed:

# I don't know the entire rationale behind this, but this is my guess.
# The purpose of protected, in the inheritance sense, is to say that
# "this property is one I wish to expose to people who need to implement
# me but not those who wish to merely use me." So, let us form the
# class:
#
# class Foo {
# protected int importantFieldForInternalUse;
# }
#
# Since it's internal, we don't want people mucking about with it, but
# our subclass needs to use it. But Joe Hacker comes along and says "if
# only I change that important field..." Since Foo is created by other
# stuff and passed around by methods, he gets a hold of it to his class:
#
# class Evil extends Foo {
# public static void manipulateFoo(Foo object) {
# // Bwa-ha-ha! I broke it all!
# object.importantFieldForInternalUse = 0;
# }
#}

Those are all good reasons.

But I think that for methods there are at least one more reason.

It is not only methods that exist in the super class that would
get exposed but also overriding virtual methods in sub classes.

public class Sup {
protected void test() {
}
}

public class SubA extends Sup {
protected void test() {
}
}

public class SubB extends Sup {
public void foobar(Sup o) {
o.test();
}
}

SubB o = new SubB();
o.foobar(new SubA());

It seems rather obvious that SubB should not have access to run
code in a protected method in SubA.

Arne
 

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

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top