简体   繁体   English

为什么我们不能用私有扩展类方法覆盖基类方法?

[英]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: One类有一个包私有的foo方法:

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 . Two类是One类的子类, foo方法被覆盖,但具有访问修饰符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. Java 语言不允许子类降低子类中方法、字段或类的可见性,因此,降低foo方法可见性的Two类是不合法的。

Why is reducing visibility a problem?为什么降低能见度是一个问题?

Consider the case where we want to use the One class:考虑我们要使用One类的情况:

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.在这里,在One实例上调用foo方法是有效的。 (Assuming that the AnotherClass class is in the same package as the One class.) (假设AnotherClass类与One类在同一个包中。)

Now, what if we were to instantiate the Two object and place it in the obj variable of the type One ?现在,如果我们要实例化Two对象并将其放在One类型的obj变量中呢?

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. Two.foo方法是私有的,但是One.foo方法允许访问该方法。 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.这段代码的问题在于,如果它是合法的,那么如果您通过One基类间接访问它,Java 将无法尊重fooprivate修饰符。 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 .然后我们会遇到麻烦,因为我们将间接调用Twoprivate方法foo ,因为当编译器检查obj.foo()它会查看One以确定foo是否可访问,而不是在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这样做的原因是编译器不能总是告诉obj可能指向什么 - 例如,如果我写了类似的东西

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 .那么编译器就无法知道obj指向One还是指向Two Consequently, it defers to One when checking access specifiers.因此,它在检查访问说明符时遵循One 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.如果我们确实被允许在Two标记foo private ,那么编译器会错误地允许我们通过obj调用它,它的类型为One ,绕过只有对象本身可以调用private方法的保证。

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.通常,类 One 是一个类的一般定义,它带有外部世界的访问器、方法。 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.在您的示例中,两个扩展了一个,这意味着两个为外部世界提供了与 One 相同的访问器。 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.如果您要更改 One 访问器的可见性,外部世界将无法再访问您的类,因为它们习惯于对类型为 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.如果你有一个 Two 实例存储在 Two 变量中,那么不能调用 foo 是有道理的。 But if you store a Two instance in a One variable, you only know about One.但是,如果将 Two 实例存储在 One 变量中,则您只知道 One。 But One's have a public foo, and that can be called.但是 One 有一个公共 foo,可以调用它。 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来引用Two的实例:

One v = new Two();

What would the program do if you called the foo method on the v reference?如果你在 v 引用上调用 foo 方法,程序会做什么? You broke the public contract of One, which guarantees that every instance of One has a (here package-protected) foo method.你破坏了 One 的公共契约,它保证 One 的每个实例都有一个(这里是包保护的)foo 方法。 That's why the compiler forbids it.这就是编译器禁止它的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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