I have a class which has a method whose access specifier by default is public. Now, I would like to extend this class in a subclass and I want to override this method to have access specifier "private". When compiling this code, I am getting a compilation error:
"attempting to assign weaker access privileges".
Could somebody please explain to me what is wrong with assigning weaker privileges in a subclass?
Here is the code that caused the compilation error:
class Superclass
{
void foo()
{
System.out.println("Superclass.foo");
}
}
class Subclass extends Superclass
{
private void foo()
{
System.out.println("Subclass.foo");
}
}
The short answer is that it is not allowed because it would break type substitutability; see also the Liskov Substititution Principle (LSP).
The point is that polymorphism in Java (and other programming languages) relies on you being able to treat an instance of a subclass as if it was an instance of the superclass. But if the method is restricted in the subclass, you find that the compiler cannot figure out whether the access rules allow a method to be called ...
For instance, lets assume that your example code was legal:
// Assume this code is in some other class ...
SuperClass s1 = new SuperClass();
s1.foo(); // OK!
SuperClass s2 = new Subclass();
s2.foo(); // What happens now?
SuperClass s3 = OtherClass.someMethod();
s3.foo(); // What happens now?
If you base the decision on whether s2.foo()
is allowed on the declared type of s2
, then you allow a call to a private
method from outside the abstraction boundary of Subclass
.
If you base the decision on the actual type of the object that s2
refers to, you cannot do the access check statically. The s3
case makes this even clearer. The compiler has absolutely no way of knowing what the actual type of the object returned by someMethod
will be.
Access checks that could result in runtime exceptions would be a major source of bugs in Java application. The language restriction under discussion here avoids this nasty problem.
You can't restrict access because you have already allowed more access in the super class. e.g.
SuperClass sc = new SubClass();
sc.foo(); // is package local, not private.
The access of sc
is determined by the type of the reference sc
not what it references because it is impossible for the compiler to know in all cases what type the object is at run time. For this to be a safe assumption the sub-class must honour the contract given by the parent or it fails to be a valid subclass. This is no different to the parent saying a method is implemented but the sub class saying it is not (or not accessible)
You could work around this by saying you can only access the sub-class method via the parent, not directly. The problem with this is you don't know when a parent might add a method and when you make a method private
you do this because you want it to be private, and not accessible another way.
BTW You can still access a private method via reflection which has the side effect that it cause all sort of problems for the JVM. e.g. it has to keep private methods even though it might determine there is no way it can be called normally.
In short, you want code which means what it says, and not have a split personality. It is either package local or it is private not something sort of in between but not really either. This is not such a problem the other way. i.e. if the sub class is public. It just means the sub-class can be used in more places than the parent, just like it can implement more 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