When overriding a method, why can I increase access but not decrease it?

JavaInheritanceAccess Modifiers

Java Problem Overview


Why does Java specify that the access specifier for an overriding method can allow more, but not less, access than the overridden method? For example, a protected instance method in the superclass can be made public, but not private, in the subclass.

Java Solutions


Solution 1 - Java

It's a fundamental principle in OOP: the child class is a fully-fledged instance of the parent class, and must therefore present at least the same interface as the parent class. Making protected/public things less visible would violate this idea; you could make child classes unusable as instances of the parent class.

Solution 2 - Java

Imagine these two classes:

public class Animal {
  public String getName() { return this.name; }
}

public class Lion extends Animal {
  private String getName() { return this.name; }
}

I could write this code:

Animal lion = new Lion();
System.out.println( lion.getName() );

And it would have to be valid, since on Animal the method getName() is public, even tho it was made private on Lion. So it is not possible to make things less visible on subclasses as once you have a superclass reference you would be able to access this stuff.

Solution 3 - Java

Because it would be weird:

class A {
    public void blah() {}
}

class B extends A {
    private void blah() {}
}


B b = new B();
A a = b;
b.blah();  // Can't do it!
a.blah();  // Can do it, even though it's the same object!

Solution 4 - Java

Take an example given below

 class Person{
 public void display(){
      //some operation
    }
 }

class Employee extends Person{
   private void display(){
       //some operation
   }
 }

Typical overriding happens in the following case

Person p=new Employee();

Here p is the object reference with type Person(super class) when we are calling p.display(). As the access modifier is more restrictive, the object reference p cannot access child object of type Employee

Solution 5 - Java

Late to the party but I would like to add one more concern related to overriding: The overriding method must allow less (or the same level of) throwable exception than the overridden method; even nothing throwable at all.

Liskov substitution principle can explain that too:

interface Actionable {
  void action() throws DislocationException;
}

public class Actor implements Actionable {
  @Override 
  public void action() throws DislocationException {
     //....
  }
} 

public class Stuntman implements Actionable {
  @Override // this will cause compiler error
  public void action() throws DislocationException, DeathException {
     //....
  }
}

// legacy code to use Actionable
try {
   Actionable actor = new Actor(); // this cannot be replaced by a Stuntman, 
                                   // or it may break the try/catch block
   actor.action();
} catch (DislocationException exc) {
   // Do something else
}

Above, the overridden method made a commitment that in the worst case it will throw the DislocationException, no more (a doctor is required at the filming location). So the overriding method must not break that, by adding more DeathException (or an ambulance is a must)

I often call the overriding rule "[can be] more access [level], [but] less exception"

Solution 6 - Java

Because a subclass is a specialization of the superclass, or in other words, it's an extension of the superclass.

Imagine for instance the toString method. All Java objects have it because the class Object has it. Imagine you could define a class with the method toString private. You then no longer treat all Objects equally. For instance, you would no longer be able to this safely:

for (Object obj : collection) System.out.println(obj);

Solution 7 - Java

Well, in terms of the specific case you mentioned, how exactly would Java handle that? If the subclass made a public/protected method private, then what should the JVM do when that method is invoked on an instance of the subclass? Honor the private and invoke the superclass' implementation? Further, you're breaking the contract specified by the superclass when you suddenly say "no one can access this method, despite what the contract initially said."

Solution 8 - Java

To re-word what's already been said, it has to do with how Java is compiled into bytecode which is then interpreted by the JVM. when a child class overrides one of its parents methods, the compiler uses the reference type to determine which of the two methods to use. Then the JVM uses the object type during runtime to determine which method should truly be used.

In the example above; Animal lion = new Lion(), when lion.getName() is called, the compiler uses the Animal version of the method and the JVM replaces it/can replace it with the Lion version because it "fits" perfectly. But if Lion were allowed to restrict getName() more than Animal restricted getName(), you could get around the restriction because the compiler would treat it like its unrestricted if a Lion object has an Animal reference.

To solve this, java makes it illegal for the child to make an overridden method more restricted than the method its overriding.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionyesilupperView Question on Stackoverflow
Solution 1 - JavaPatrick87View Answer on Stackoverflow
Solution 2 - JavaMaurício LinharesView Answer on Stackoverflow
Solution 3 - JavaOliver CharlesworthView Answer on Stackoverflow
Solution 4 - JavaVineeth BhaskaranView Answer on Stackoverflow
Solution 5 - JavaU and meView Answer on Stackoverflow
Solution 6 - JavaJoão FernandesView Answer on Stackoverflow
Solution 7 - JavaMarvoView Answer on Stackoverflow
Solution 8 - JavaBen TronoView Answer on Stackoverflow