Why can't we assign weaker privileges in a subclass

I have a class that has a method whose default access specifier is public. Now I would like to extend this class in a subclass, and I want to override this method to get the "private" access specifier. When compiling this code, I get a compilation error:

"trying to assign weaker permissions."

Can someone 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"); } } 
+11
java inheritance
source share
8 answers

The short answer is that it is not valid because it violates type substitution; see also Liskov Substitution Principle (LSP).

The fact is that polymorphism in Java (and other programming languages) is based on the fact that you can consider an instance of a subclass as if it were an instance of a superclass. But if the method is limited to a subclass, you will find that the compiler cannot determine if the access rules allow the method that is being called ...

For example, suppose your sample 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 s2.foo() acceptability decision on the declared type s2 , you allow the private method to be private from outside the Subclass abstraction.

If you base your decision on the actual type of object referenced by s2 , you cannot do access verification statically. Case s3 makes this even clearer. The compiler has absolutely no way of knowing what the actual type of the object returned by someMethod .

Access checks that may lead to runtime exceptions will be a major source of errors in a Java application. The language restriction discussed here avoids this annoying problem.

+27
source share

You cannot restrict access because you have already allowed more access in the superclass. eg.

 SuperClass sc = new SubClass(); sc.foo(); // is package local, not private. 

Access to sc determined by the type of link sc , and not what it refers to, because the compiler cannot know in all cases what type of object is at run time. For this to be a safe assumption, the subclass must fulfill the contract provided by the parent, or it cannot be a valid subclass. This is no different from the parent saying that the method is implemented, but a subclass saying that it (or is not available)

You can get around this by saying that you can access the subclass method only through the parent, and not directly. The problem is that you do not know when the parent can add the method, and when you create the private method, you do this because you want it to be private and inaccessible in another way.

BTW You can still access the private method using reflection, which has a side effect that causes all kinds of problems for the JVM. for example, it must support private methods, even if it can determine that it cannot be called normally.

In short, you want the code to mean what it says and not have a forked personality. This is either a local package, or it is not private, and not something like a gap between them, but not really. This is not such a problem. that is, if the subclass is publicly available. It just means that the subclass can be used in more places than the parent, just as it can implement more methods.

+8
source share

If it were allowed, there would be a backdoor through which you could call methods that should not be available.

Assume this is allowed

 class Super { public void method() { System.out.println("Super"); } } class Sub extends Super { // This is not allowed, but suppose it was allowed protected void method() { System.out.println("Sub"); } } // In another class, in another package: Super obj = new Sub(); obj.method(); 

obj.method would be possible because method() is public in the Super class. But this should not be allowed, because obj really refers to an instance of Sub, and in this class the method is protected!

To limit the method call in the Sub class, which should not be accessible externally, this restriction is imposed.

+6
source share

The restriction of the access modifier of a superclass method is an invalid override because it violates the contract of the superclass and cancels the substitution principle, i.e. a superclass class object of a sub-class object.

 public void doSomething(SuperClass sc) { sc.publicMethodInSuperClass(); } doSomething(new SubClass()); // would break 

If it was allowed, the above client code will break because your SubClass does not have this public method.

Link:
Liskov substitution principle

+1
source share

Besides the obvious problems with using such constructs (as Peter Lowry pointed out in his answer), read also about this theory: LSP , which means that you should be able to substitute the main type with your subclass.

0
source share

I think the short answer is that the authors of the compiler set the rules for working this way. LSP has nothing to do with the problem.

The only reason I can think of this limitation is that when a subclass comes from an interface, as a client programmer, you expect that you can call all available interface methods from a reference to a derived class.

Suppose you could write code that showed OP. If you have a reference to a derived class, you should be able to call any public members of the derived class (although in this case they are not). However, pass the link as a parameter to a method that references the base class, and the method will wait for any public or batch method that is equal to foo called. This is the LSP that other members are looking for!

C ++ example:

 class Superclass{ public: virtual void foo(){ cout << "Superclass.foo" << endl; } }; class Subclass: public Superclass{ virtual void foo(){ cout << "Subclass.foo" << endl; } }; int main(){ Superclass s1; s1.foo() // Prints Superclass.foo Subclass s2; // s2.foo(); // Error, would not compile Superclass& s1a=s2; // Reference to Superclass 'pointing' to Subclass s1a.foo(); // Compiles OK, Prints Subclass.foo() } 
0
source share

When sending a dynamic method, the call to the overridden method is allowed at run time, not compile time. It is based on the object referenced during the call ...

Now suppose that a weaker access privilege has been allowed, and we write the following statement in your code:

 Superclass ref=new Subclass(); ref.foo() 

Now at runtime, when java encounters the ref.foo() operator, it will have to call foo() from Subclass ... but the subclass method foo() declared as private in your code, and private can not be called outside its own class. .. and now there is a conflict, and this will lead to a runtime exception ...

0
source share

Since you changed the order of access rights, you received an error

correct order: ==> private default protected public

* in your case you go by default ==> private when you go in the wrong order, this leads to an error

The correct order of access privileges is--

 'class SuperClass{ void foo(){ System.out.print("SuperClass"); } class SubClass extends{ //--default to default--// void foo(){ System.out.print("SubClass"); } //--default to protected--// protected void foo(){ System.out.print("SubClass"); //--default to public // public void foo(){ System.out.print("SubClass"); }' **you make sure to preserve correct order while overriding ** 
-one
source share

All Articles