class One {
void foo() { }
}
class Two extends One {
private void foo() { /* more code here */ }
}
Why is the above snippet of code wrong?
I'm going to try to incorporate the ideas from the other answers to come up with a single answer.
First off, let's take a look at what's going on in the code.
A look at the code
The One
class has a package-private foo
method:
class One {
// The lack of an access modifier means the method is package-private.
void foo() { }
}
The Two
class which subclasses the One
class, and the foo
method is overriden, but has the access modifier private
.
class Two extends One {
// The "private" modifier is added in this class.
private void foo() { /* more code here */ }
}
The issue
The Java language does not allow subclasses to reduce the visibility of a method, field or class in a subclass, therefore, the Two
class reducing the visibility of the foo
method is not legal.
Why is reducing visibility a problem?
Consider the case where we want to use the One
class:
class AnotherClass {
public void someMethod() {
One obj = new One();
obj.foo(); // This is perfectly valid.
}
}
Here, calling the foo
method on the One
instance is valid. (Assuming that the AnotherClass
class is in the same package as the One
class.)
Now, what if we were to instantiate the Two
object and place it in the obj
variable of the type One
?
class AnotherClass {
public void someMethod() {
One obj = new Two();
obj.foo(); // Wait a second, here...
}
}
The Two.foo
method is private, yet, the One.foo
method would allow the access to the method. We've got a problem here.
Therefore, it doesn't make much sense to allow reduction of visibility when taking inheritance into account.
Links
The problem with this code is that if it were legal, Java wouldn't be able to respect the private
modifier of foo
if you accessed it indirectly through the One
base class. For example, if I were to write
One obj = new Two();
obj.foo();
Then we'd be in trouble because we'd be calling the private
method foo
of Two
indirectly, since when the compiler checks the line obj.foo()
it looks at One
to determine if foo
is accessible, not at Two
. The reason for this is that the compiler can't always tell what obj
could be pointing at - if, for example, I write something like
One obj = Math.random() < 0.5? new One() : new Two();
obj.foo();
Then the compiler can't know whether obj
points at a One
or a Two
. Consequently, it defers to One
when checking access specifiers. If we were indeed allowed to mark foo
private in Two
, then the compiler would incorrectly allow us to call it through obj
, which has type One
, bypassing the guarantee that only the object itself can call private
methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With