【问题标题】:Java: Why could base class method call a non-exist method?Java:为什么基类方法可以调用不存在的方法?
【发布时间】:2010-12-29 08:52:59
【问题描述】:
class BaseClass {
    private void f() {
        System.out.println("Baseclass f()");
    }

    public static void main(String[] args) {
        BaseClass dc = new DerivedClass();
        dc.f();
    }
}

class DerivedClass extends BaseClass {
    public void f() {
        System.out.println("DerivedClass f()");
    }
}

在我看来,dc 引用的对象应该只有一个 non-override 方法 - public void f() 方法,这使得它(公共方法)在使用 BaseClass 引用时不可见.既然dc引用的对象没有private void f()方法,也因为DeriverClass不能继承私有方法,那么dc引用的对象怎么可能调用f()方法呢?

谢谢。

【问题讨论】:

  • 为什么要在基类的方法中声明派生类的变量? o.0
  • 我在 Thinking in Java 中发现了这种代码。我认为这是深入挖掘 Java 编程语言核心的一个有价值的例子。
  • 你说的是public void f()。这不会发生在任何课程中。是虚构的方法吗?那么它将属于哪个类?
  • 对不起。我忘记了 public 关键字。

标签: java inheritance polymorphism


【解决方案1】:

一个常见的(ish)误解是私有是每个实例而不是每个类。

例如:

class Foo
{
    private int a;

    public bar(final Foo other)
    {
        other.a = 5;
    }
}

有些人认为上面的代码不应该工作,因为“a”是“private”。事实并非如此,任何 Foo 实例都可以访问任何其他 Foo 实例的私有变量/方法。 “private”只是意味着其他类的实例(在这种情况下除了 Foo 之外)不能访问私有成员。

【讨论】:

  • 为什么Java允许这种语法?
  • 因为它在技术上是在同一个范围内。
  • c++ 做同样的事情...我不知道有任何语言可以在对象级别提供保护(并不意味着没有,有很多我不知道:- )。
  • Ruby 就是这样:私有适用于对象,而不是类。在 Scala 中,两种可见性级别都存在(语法是 private 和 private[this])
【解决方案2】:

为了保持直截了当,DerivedClass (DC) 确实从 BaseClass (BC) 继承 private void f()。 DC 无法访问此继承的方法,但它存在是因为在 DC 的 BC 部分中调用的任何方法都必须有权访问所有 BC。因此,当您将 DC 转换为 BC 时,继承的方法变得可用。现在因为您在 BC 类中运行代码,所以它可以访问 BC 的所有私有成员。如果您将 main 移至 DC,则它不应该编译,更不用说运行了。

【讨论】:

    【解决方案3】:

    四点:

    (1) 详细说明 vivyzer 写的内容,代码编译是因为 BaseClass 中的 main 方法可以访问该类自己的私有方法。如果你把代码写成:

    class BaseClass {
      private void f() { }
    }
    
    class DerivedClass {
      public void f() { }
    }
    
    class Bystander {
      public static void main() {
        BaseClass inst = new DerivedClass();
        inst.f();
      }
    }
    

    那么代码将无法编译。

    (2) 语言允许这样做以支持基类的作者可以添加新的私有方法而无需担心其他作者的派生类型的用例。

    (3) 如果方法不是私有的,你不会看到这个。如果基类的 f() 具有包或受保护的可见性,则该方法将是虚拟方法。

    (4) Java 不支持第 2 点的反面。具体来说,如果派生类有私有方法,而新版本的基类引入了具有相同签名的非私有方法,则派生类和新基类不能一起使用。还有其他语言(例如 C#)可以更完整地解决这些模块化的、世代相传的开发问题。如果您对这方面感兴趣,这是关于 Artima 的好书:Versioning, Virtual, and Override

    【讨论】:

    • 类 DerivedClass 应该扩展 BaseClass。
    【解决方案4】:

    主要方法在 BaseClass 内部,私有方法对其可见。如果 main 在某个其他类中,它将无法编译。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-31
      • 2014-07-17
      • 1970-01-01
      • 2013-07-17
      • 2013-10-08
      • 2013-08-20
      • 2018-07-11
      • 1970-01-01
      相关资源
      最近更新 更多