+ 3
Why can't the access level of the overiding method be more restrictive than that of the overidden method?
- The access level cannot be more restrictive than the overridden method's access level (Example: If the superclass method is declared public, the overriding method in the sub class can be neither private or protected.AGAIN WHY CAN IT BE LESS RESTRICTIVE?
2 Réponses
+ 1
This is an excellent question!
It is maybe more helpful to consider 1st what happens in the opposite direction i.e. to relax the access level in the overriding method. For example:
class A
{
private int foo(int x){
return x;
}
}
class B extends A
{
public int foo(int x){
return x*x;
}
}
Instantiating and calling an object like this...
A b = new B();
int z = b.foo(5);
... the compiler fails with "foo(int) has private access in A: int z = b.foo(5); "
This implies the compiler uses the foo access level in A for the method, and not in B.
Interestingly, you get exactly the same behaviour in C++ - the compiler fails with "'virtual int A::foo(int)' is private"
So, in both Java and C++ the access level of the variable type applies(A), and not the instantiated class (B).
So what happens in the opposite direction?
class A
{
public int foo(int x){
return x;
}
}
class B extends A
{
private int foo(int x){
return x*x;
}
}
As stated by the OP, the Java compiler fails with "attempting to assign weaker access privileges".
But, interestingly, the C++ compiler is happy with this and the program compiles and runs!!! C++ is actually consistent in using the access level of the variable type as before and, since it is public, the compiler is happy!
So who is right? On http://stackoverflow.com/questions/17510152/why-cant-we-assign-weaker-privilege-in-subclass there is a discussion about this and the accepted answers all argue based on the Liskov substitution principle (see https://en.wikipedia.org/wiki/Liskov_substitution_principle).
I however cannot see how this favours Java's behaviour. In fact, it looks like the principle applies more to the way C++ does it since B (subclass) can definitely be substituted for A (superclass). I would argue that Java in fact does not comply with the LSP!
Short answer: I think Java should allow it, in is in error not to!
+ 1
Checking the same behaviour in C# shows C# to be more strict than either Java or C++. An overriding function cannot change the access level of the overridden function at all - they have to be exactly the same. And it does not matter if the access level becomes more strict or more relaxed - the compiler error is the same.
This is definitely the most consistent and safest position to take (definitely the principle of least surprise).
Having thought about it, I can also now see one instance where C++ will not comply with the LSP (where A::foo is public, B::foo is private) :
A*a = new A;
//Modify above to...
A* a = new B; //LSP pass, B substitutes A,
//this is polymorphic behaviour ...
a->foo(5);
But this case fails:
A*a = new A;
//Modify above to...
B*à = new B;
a->foo(5);//Fails to compile (B::foo is private), LSP therefore fails (but substituting both the type and instance type means this is not polymorphic) .