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

发布于 2024-10-20 13:52:19 字数 155 浏览 1 评论 0原文

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

为什么上面的代码片段是错误的?

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

Why is the above snippet of code wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

失去的东西太少 2024-10-27 13:52:19

我将尝试结合其他答案的想法来得出一个答案。

首先,让我们看一下代码中发生了什么。

看一下代码

One 类有一个包私有的 foo 方法:

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

Two 类是One 类,并且 foo 方法被重写,但具有访问修饰符 private

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

问题

Java 语言不允许子类降低子类中方法、字段或类的可见性,因此,Two 类降低了>foo 方法不合法。

为什么降低可见性是一个问题?

考虑一下我们想要使用 One 类的情况:

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

在这里,调用 foo 方法>一个实例有效。 (假设 AnotherClass 类与 One 类位于同一个包中。)

现在,如果我们要实例化 Two 对象并将其放入 One 类型的 obj 变量中吗?

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

Two.foo 方法是私有的,但是 One.foo 方法将允许访问该方法。我们这里有问题。

因此,在考虑继承时允许降低可见性没有多大意义。

链接

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

陈独秀 2024-10-27 13:52:19

这段代码的问题是,如果它是合法的,如果您通过 One 间接访问它,Java 将无法尊重 fooprivate 修饰符基类。例如,如果我写

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

Then 我们就会遇到麻烦,因为我们会间接调用 Twoprivate 方法 foo,因为当编译器检查 obj.foo() 行时,它会查看 One 来确定 foo 是否可访问,而不是查看 Two。原因是编译器不能总是知道 obj 可能指向什么 - 例如,如果我写了类似的内容

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

那么编译器无法知道 obj 是否指向code> 指向 OneTwo。因此,在检查访问说明符时它遵循 One。如果我们确实被允许在 Two 中将 foo 标记为私有,那么编译器将错误地允许我们通过 obj 调用它,其类型为 < code>One,绕过了只有对象本身才能调用 private 方法的保证。

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.

找个人就嫁了吧 2024-10-27 13:52:19

给出的答案为您提供了为什么不能将一乘二扩展的技术解释。我想让您理解为什么这是不可能的,因为面向对象的模式而不是语言本身。

通常,类 One 是一个类的一般定义,及其对外部世界的访问器、方法。扩展此类的子类必须向外部世界提供相同的访问器。在您的示例中,二扩展了一,这意味着二提供了与一一样的外部世界访问器。如果您要更改 One 访问器的可见性,外部世界将无法再访问您的类,因为它们用于对类型 One 的对象执行此操作。

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.

神魇的王 2024-10-27 13:52:19

它会破坏多态性。

如果您有一个 Two 实例存储在 Two 变量中,那么 foo 无法被调用是有道理的。但是,如果将 Two 实例存储在 One 变量中,则您只知道 One。但是 One 有一个公共 foo,可以调用它。这会是一种不一致,而且会很奇怪。

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.

冷情妓 2024-10-27 13:52:19

因为继承是一种关系。任何人都可以通过对 One 的引用来引用 Two 的实例:

One v = new Two();

如果您在 v 引用上调用 foo 方法,程序会做什么?您破坏了 One 的公共契约,该契约保证 One 的每个实例都有一个(此处受包保护的)foo 方法。这就是编译器禁止它的原因。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文