My Pages

Monday, June 14, 2010

Java Protected and Default Members

The protected and default access control
levels are almost identical, but with one critical difference. A default member may be accessed only if the class accessing the member belongs to the same package,
whereas a protected member can be accessed (through inheritance) by a subclass
even if the subclass is in a different package. Take a look at the following two classes:

package certification;
public class OtherClass {
void testIt() { // No modifier means method has default access
System.out.println("OtherClass");
}
}

In another source code file you have the following:

package somethingElse;
import certification.OtherClass;
class AccessClass {
static public void main(String [] args) {
OtherClass o = new OtherClass();
o.testIt();
}
}

As you can see, the testIt() method in the second file has default (think:package-level) access. Notice also that class OtherClass is in a different package from the AccessClass. Will AccessClass be able to use the method testIt()?
Will it cause a compiler error? Will Daniel ever marry Francesca? Stay tuned.

%javac AccessClass.java
AccessClass.java:5: No method matching testIt() found in class
certification.OtherClass.
o.testIt();
1 error

From the preceding results, you can see that AccessClass can’t use the OtherClass method testIt() because testIt() has default access, and AccessClass is not in the same package as OtherClass. So AccessClass can’t see it, the compiler complains, and we have no idea who Daniel and Francesca are.
Default and protected behavior differ only when we talk about subclasses. This difference is not often used in actual practice, but that doesn’t mean it won’t be on the exam! Let’s look at the distinctions between protected and default access.
If the protected keyword is used to define a member, any subclass of the class declaring the member can access it. It doesn’t matter if the superclass and subclass are in different packages, the protected superclass member is still visible to the subclass (although visible only in a very specific way as we’ll see a little later). This is in contrast to the default behavior, which doesn’t allow a subclass to access a superclass member unless the subclass is in the same package as the superclass.

Whereas default access doesn’t extend any special consideration to subclasses (you’re either in the package or you’re not), the protected modifier respects the parent-child relationship, even when the child class moves away (and joins a new package). So, when you think of default access, think package restriction. No exceptions. But when you think protected, think package + kids. A class with a protected member is marking that member as having package-level access for all
classes, but with a special exception for subclasses outside the package.
But what does it mean for a subclass-outside-the-package to have access (visibility) to a superclass (parent) member? It means the subclass inherits the member. It does not, however, mean the subclass-outside-the-package can access the member using a reference to an instance of the superclass. In other words, protected = inheritance.Protected does not mean that the subclass can treat the protected superclass member as though it were public. So if the subclass-outside-the-package gets a reference to the superclass (by, for example, creating an instance of the superclass somewhere in the subclass’ code), the subclass cannot use the dot operator on the superclass reference to access the protected member. To a subclass-outside-the-package, a
protected member might as well be default (or even private), when the subclass is using a reference to the superclass. The subclass can only see the protected member through inheritance.
Are you confused? So are we. Hang in there and it will all become clear with the next batch of code examples. (And don’t worry; we’re not actually confused. We’re just trying to make you feel better if you are. You know, like it’s OK for you to feel as though nothing makes sense, and that it isn’t your fault. Or is it? ) Let’s take a look at a protected instance variable (remember, an instance variable is a member) of a superclass.

package certification;
public class Parent {
protected int x = 9; // protected access
}

The preceding code declares the variable x as protected. This makes the variable accessible to all other classes in the certification package, as well as inheritable by any subclasses outside the package. Now let’s create a subclass in a different package, and attempt to use the variable x (that the subclass inherits).

package other; // Different package
import certification.Parent;
class Child extends Parent {
public void testIt() {
System.out.println("x is " + x); // No problem; Child inherits x
}
}

The preceding code compiles fine. Notice, though, that the Child class is accessing the protected variable through inheritance. Remember, anytime we talk about a subclass having access to a superclass member, we could be talking about the subclass inheriting the member, not simply accessing the member through a reference to an instance of the superclass (the way any other nonsubclass would access it). Watch what happens if the subclass Child (outside the superclass’ package) tries to access a protected variable using a Parent class reference.
package other;

import certification.Parent;
class Child extends Parent {
public void testIt() {
System.out.println("x is " + x); // No problem; Child inherits x
Parent p = new Parent(); // Can we access x using the p reference?
System.out.println("X in parent is " + p.x); // Compiler error!
}
}

The compiler is more than happy to show us the problem:
%javac -d . other/Child.java
other/Child.java:9: x has protected access in certification.Parent
System.out.println("X in parent is " + p.x);
^
1 error

So far we’ve established that a protected member has essentially package-level or default access to all classes except for subclasses. We’ve seen that subclasses outside the package can inherit a protected member. Finally, we’ve seen that subclasses outside the package can’t use a superclass reference to access a protected member.For a subclass outside the package, the protected member can be accessed only through inheritance.
But there’s still one more issue we haven’t looked at…what does a protected member look like to other classes trying to use the subclass-outside-the-package to get to the subclass’ inherited protected superclass member? For example, using our previous Parent/Child classes, what happens if some other class—Neighbor, say— in the same package as the Child (subclass), has a reference to a Child instance and wants to access the member variable x ? In other words, how does that protected member behave once the subclass has inherited it? Does it maintain its protected
status, such that classes in the Child’s package can see it? No! Once the subclass-outside-the-package inherits the protected member, that member (as inherited by the subclass) becomes private to any code outside the subclass. So if class Neighbor instantiates a Child object, then even if class Neighbor is in the same package as class Child, class Neighbor won’t have access to the Child’s inherited (but protected) variable x. The bottom line: when a
subclass-outside-the-package inherits a protected member, the member is essentially
private inside the subclass, such that only the subclass’ own code can access it.
Figure 2-3 illustrates the effect of protected access on classes and subclasses in the
same or different packages.
Whew! That wraps up protected, the most misunderstood modifier in Java.
Again, it’s used only in very special cases, but you can count on it showing up on
the exam. Now that we’ve covered the protected modifier, we’ll switch to default
member access, a piece of cake compared to protected.
Let’s start with the default behavior of a member in a superclass. We’ll modify
the Parent’s member x to make it default.

package certification;
public class Parent {
int x = 9; // No access modifier, means default (package) access
}

Notice we didn’t place an access modifier in front of the variable x. Remember that if you don’t type an access modifier before a class or member declaration, the access control is default, which means package level. We’ll now attempt to access the default member from the Child class that we saw earlier. When we compile the Child file, we get the following error:

%javac Child.java
Child.java:4: Undefined variable: x
System.out.println("Variable x is " + x);
1 error

The compiler gives the same error as when a member is declared as private.
The subclass Child (in a different package from the superclass Parent) can’t see or use the default superclass member x ! Now, what about default access for two classes
in the same package?

package certification;
public class Parent{
int x = 9; // default access
}

And in the second class you have the following:
package certification;

class Child extends Parent{
static public void main(String [] args) {
Parent sc = new Parent();
sc.testIt();
}
public void testIt() {
System.out.println("Variable x is " + x); // No problem;
}
}

The preceding source file compiles fine, and the class Child runs and displays the value of x. Just remember that default members are visible only to the subclasses that are in the same package as the superclass.