简体   繁体   中英

Why can’t we override a base class method with private extended class method?

class One {
    void foo() { }
}
class Two extends One {
    private void foo() { /* more code here */ }
}

Why is the above snippet of code wrong?

I'm going to try to incorporate the ideas from the other answers to come up with a single answer.

First off, let's take a look at what's going on in the code.

A look at the code

The One class has a package-private foo method:

class One {
    // The lack of an access modifier means the method is package-private.
    void foo() { }
}

The Two class which subclasses the One class, and the foo method is overriden, but has the access modifier private .

class Two extends One {
    // The "private" modifier is added in this class.
    private void foo() { /* more code here */ }
}

The issue

The Java language does not allow subclasses to reduce the visibility of a method, field or class in a subclass, therefore, the Two class reducing the visibility of the foo method is not legal.

Why is reducing visibility a problem?

Consider the case where we want to use the One class:

class AnotherClass {
  public void someMethod() {
     One obj = new One();
     obj.foo();  // This is perfectly valid.
  }
}

Here, calling the foo method on the One instance is valid. (Assuming that the AnotherClass class is in the same package as the One class.)

Now, what if we were to instantiate the Two object and place it in the obj variable of the type One ?

class AnotherClass {
  public void someMethod() {
     One obj = new Two();
     obj.foo();  // Wait a second, here...
  }
}

The Two.foo method is private, yet, the One.foo method would allow the access to the method. We've got a problem here.

Therefore, it doesn't make much sense to allow reduction of visibility when taking inheritance into account.

Links

The problem with this code is that if it were legal, Java wouldn't be able to respect the private modifier of foo if you accessed it indirectly through the One base class. For example, if I were to write

One obj = new Two();
obj.foo();

Then we'd be in trouble because we'd be calling the private method foo of Two indirectly, since when the compiler checks the line obj.foo() it looks at One to determine if foo is accessible, not at Two . The reason for this is that the compiler can't always tell what obj could be pointing at - if, for example, I write something like

One obj = Math.random() < 0.5? new One() : new Two();
obj.foo();

Then the compiler can't know whether obj points at a One or a Two . Consequently, it defers to One when checking access specifiers. If we were indeed allowed to mark foo private in Two , then the compiler would incorrectly allow us to call it through obj , which has type One , bypassing the guarantee that only the object itself can call private methods.

The given answers give you the technical explanation why you cannot extend One by Two. I would like to give you an understanding why this is not possible due to the object oriented pattern and not because of the language itself.

Usually the class One is a general definition of a class with its accessors, the methods, to the outer world. Sublcasses which extend this class must provide the same accessors to the outer world. Two extends One in your example, what means, that Two provides the same accessors to the outer world like One does. If you would change the visibility of the accessors of One, the outer world could no longer access your class as they are used to do it with an object of type One.

It would break polymorphism.

If you have a Two instance stored in a Two variable, then it would make sense that foo cannot be called. But if you store a Two instance in a One variable, you only know about One. But One's have a public foo, and that can be called. This would be an inconsistency and would be really weird.

Because inheritance is a is a relationship. Anyone could refer to a instance of Two through a reference to One :

One v = new Two();

What would the program do if you called the foo method on the v reference? You broke the public contract of One, which guarantees that every instance of One has a (here package-protected) foo method. That's why the compiler forbids it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM