Why Can't You Reduce the Visibility of a Method in a Java Subclass

Why can't you reduce the visibility of a method in a Java subclass?

Because every instance of the subclass still needs to be a valid instance of the base class (see Liskov substitution principle).

If the subclass suddenly has lost one property of the base class (namely a public method for example) then it would no longer be a valid substitute for the base class.

Cannot reduce visibility of method inherited method from parent

It's because the subclass has visibility of private for the void func() method, but the superclass has visibility public.

If your code was allowed to compile, it would explode at runtime if you did this:

parent p = new TestClass();
p.func(); // boom - func is public in parent, but TestClass's impl is private, so no access would be allowed

To "fix" this, make the subclass's func method public:

public class TestClass extends parent {
...
public void func() { // give it public visibility
System.out.println("in child");
}
}



And please use standard naming conventions; in this case "classes should start with a capital letter" - i.e Parent not parent

Why can we reduce visibility of a property in extended class?

This is because Parent.a and Child.a are different things. Child#method() @Overrides Parent#method(), as they are methods. Inheritance does not apply to fields.

From the Oracle JavaTM Tutorials - Inheritance, it was written that:

What You Can Do in a Subclass

  • The inherited fields can be used directly, just like any other fields.
  • You can declare a field in the subclass with the same name as the one in the superclass, thus hiding it (not recommended).
  • You can declare new fields in the subclass that are not in the superclass.

Why Java allows increasing the visibility of protected methods in child class?

Why decreasing visibility is not allowed is already explained in other responses (it would break the contract of the parent class).

But why it is allowed to increase the visibility of a method? First, it would not break any contract, so there is no reason to not allow it. It can be handy sometimes, when it makes sense in the child class for a method to not be protected.

Second, not allowing it could have the side effect of making impossible sometimes to extend a class and implement an interface at the same time:

interface Interface1 {
public void method();
}

public class Parent {
protected abstract void method();
}

public class Child extends Parent implements Interface1 {
@Override
public void method() {
}
//This would be impossible if the visibility of method() in class Parent could not be increased.
}

About your second question, you can do nothing about it. You have to trust that the person who implements the child class doesn't do anything that breaks your implementation. Even if java wouldn't allow to increase visibility, that would still not fix your problem, because a public method with a different name could be created that calls the abstract method:

class Child extends Base{
@Override
protected void a(){

}

public void a2() {
a(); //This would have the same problems that allowing to increase the visibility.
}
}

Java, Cannot reduce the visibility of the inherited method from object

Two options:

If you need B to keep the same interface as A (so that client code can use any of the two without changes), you can override "forbidden" methods in B and have them throw an UnsupportedOperationException. For example:

public class A
{
public int allowedMethod() { ... }
public int forbiddenMethod() { ... }
}

public class B extends A
{
public int forbiddenMethod()
{
throw new UnsupportedOperationException("Sorry, not allowed.");
}
}

Or, if you really want the API of B to be a subset of the API of A, then just have B contain an instance of A, and delegate method calls appropriately.

    public class A
{
public int allowedMethod() { ... }
public int forbiddenMethod() { ... }
}

public class B
{
private A a;

public int allowedMethod()
{
return a.allowedMethod();
}
}

Changing visibility of method in inherited class

If you extend (or implement) from a class (or interface) then the parent will specify the whole signature of a method. There is nothing you can change about it, you will always need to have the method public if your parent specifies it as public.

Otherwise you would run into problems when casting like ((Parent) child).theMethod(). The object itself is child but the view gets reduced to the Parent class. The method gets invoked from the child class, so it would be private although you casted it to Parent which specified it as public.

However you could do something like:

public class Child extends Parent {
@Override
public void theMethod() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

private void otherMethod {
// Do something
}
}

But note that saying "I am extending class XY but not supporting all of its methods" is not the best design. It is a sign that the parent class (or other parts of the architecture) could have been structured more modular in the first place.

Why can i increase the visibility of a overridden method in a subclass, is it not a security risk?

Access modifiers are not meant for security. You can call even a private method through reflection anyway. They are meant for encapsulation which shields from programming errors and enforces good programming style to a certain degree.

Even if you couldn't make overridden methods public, you could still do this:

class SomeApi
{
void someImportantInnerApiMethod()
{
//some operation
}
}

class MaliciousUserClass extends SomeApi
{
public void aMethodWithATotallyDifferentName()
{
// ... that still exposes that important inner API method!
super.someImportantInnerApiMethod();
}
}

Since you can make it “accessible” in this way, the only thing that Java does is allow you to do exactly the same thing while keeping the method name, if you really want to do this. No harm done because you usually don't do this kind of thing accidentally.

It is also probably worth mentioning that package-private access is ridiculously easy to circumvent: unlike .Net's internal, you can really put your classes in the same package as another library you're using, and you're free to call package-private methods! Say, you declare your class to be a part of javax.swing package, now it can call Swing's package-private methods. So much for security. You don't even need inheritance and/or reflection.

Hiding methods in subclass

Is it possible to hide methods from this superclass in an subclass inheriting from this superclass?

If you make the method private in the super class, it won't be visible in the subclass (or to any one else).

If you need the method in the base class to be public however, there is no way of hiding it in the subclass by for instance overriding it with a private implementation. (You can't "reduce visibility", i.e. go from for instance public or protected to private in a subclass.)

The best workaround is probably to override the method and throw for a runtime exception such as UnsupportedOperationException.

is it possible to change the number of arguments for a method in the subclass which has the same name in the superclass?

No, you can't change the signature. You can create another method with the same name and a different number of arguments but this would be a different (overloaded) method and the method in the base class would still be visible.



Related Topics



Leave a reply



Submit