【问题标题】:static and instance method in java -Parent and Sub classjava - 父类和子类中的静态和实例方法
【发布时间】:2015-12-30 07:16:34
【问题描述】:

为什么我们不能在子类 B 中声明与父类 A 中的静态方法具有相同签名的实例方法?

如果我尝试这样做,它会引发编译时错误。

我的问题是,既然父类的静态方法仅限于父类,为什么子类的实例方法不能编译。

让我们看代码:

`

public class A{
     static void testStatic(){}
}


public class B extends  A{
      void testStatic (){}
}


public class Test{

public static void main (String[] args){

        A a = new B()

        a.testStatic();

}

`

在上面的代码中,由于 A 没有该名称的实例方法,并且由于 Java 允许对象访问静态方法,指向 'B' 的类型为 'A' 的对象 a 可以调用存在于它(A级)。但是编译器抛出错误“实例方法无法覆盖静态方法”为什么?

注意:如果一个类不允许两个方法使用相同的方法名,我可以理解,即使一个是实例,另一个是静态的。但我不明白为什么它不允许子类有一个同名的实例。特别是考虑到静态方法不能被覆盖的事实。而Java允许子类与父类静态方法同名,称为信息隐藏,但不能覆盖。

【问题讨论】:

标签: java inheritance static


【解决方案1】:

编译器会抛出错误,因为这些是语言的规则。来自Java Language Specification §8.4.8.2

如果类 C 声明或继承了 static 方法 m,则称 m 隐藏任何方法 m',其中 m 的签名是子签名(§8.4.2) m' 的签名,在 C 的超类和超接口中,否则 C 中的代码可以访问。

静态方法隐藏实例方法是编译时错误。

(强调原文)。语言很密集(就像 JLS 中的大多数地方一样),但它与您描述的情况相匹配。 JLS 没有提供我在初读时可以找到的这条规则的基本原理。但稍微想一想人们可能会如何尝试使这条规则变得不必要,就会发现它存在的原因。

【讨论】:

  • 感谢您的回答。我可以理解一个类是否不允许两个方法使用相同的方法名称,即使一个是实例而另一个是静态的。但我不明白为什么它不允许子类有一个同名的实例。特别是考虑到静态方法不被继承,不能被覆盖的事实。而Java允许子类与父类静态方法同名,称为信息隐藏,但不能覆盖。
  • 假设你的类B中的一些其他代码包含一个调用testStatic();。编译器应该如何判断您是指this.testStatic();(实例方法调用)还是A.testStatic();(静态方法调用)?请注意,即使是 JLS 也使用暗示 static 方法是继承的语言。使用B.testStatic() 访问A.testStatic() 是合法的(尽管lint 工具会对此发出警告)。这只是一个猜测,但我认为语言设计者认为允许实例方法隐藏您所描述的 static 方法太难了。
【解决方案2】:

它在 Java 中是非法的。在实例上也允许调用静态方法,因此在某些情况下无法区分调用哪个方法:

  A a = new A ();
  B b = new B ();
  A.testStatic (); // ok
  B.testStatic (); // ok
  a.testStatic (); // ok calling static
  b.testStatic (); // undefined. What to call? Based on what?

最后一次通话是不允许的原因。

【讨论】:

  • 为什么最后一行不能在B类中调用testStatic实例方法?
  • 那么在调用之前会排什么?这种情况是未定义的,因此设置语言以通过发出编译错误来防止这种情况发生。
  • 我的意思是,如果 B 有 testStatic 作为静态方法,那么编译器允许它并且 b.testStatic 调用 B 类的静态方法。为什么不能在这里遵循相同的方式?
  • 如果 B 的方法也是静态的,它会隐藏 A 在所有情况下的方法 - 从我的列表中调用 2 和 4。但在非静态情况下,情况并非如此。
【解决方案3】:

static 方法的调用在编译时自行解决。因此,它们不能被覆盖。并且通过定义另一个与静态方法具有相同签名的方法,编译器会抱怨。

【讨论】:

  • 你可以在子类中定义同名的,即使它是一个静态方法。它被称为信息隐藏。但我的情况不同。
【解决方案4】:

静态方法与类绑定,而实例方法与对象绑定。 静态属于类区,实例属于堆区。

【讨论】:

    【解决方案5】:
    我不是百分百肯定,但我猜答案如下。

    静态方法意味着它可以在没有定义它的类的实例的情况下使用。静态方法也只能访问类的静态变量。现在如果我们重写非静态方法并引用超类创建子类的实例,编译器会混淆上述两个静态方法的基本功能。请讨论这是否有任何问题。

    【讨论】:

      【解决方案6】:

      4 行显示错误。所以这样做 公共类 B 扩展 A

      【讨论】:

        猜你喜欢
        • 2018-03-07
        • 2022-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多