【问题标题】:Java - Hiding Overriding and the modifier finalJava - 隐藏覆盖和修饰符 final
【发布时间】:2016-05-12 18:24:51
【问题描述】:

我找不到像我这样的问题,所以我希望它不是重复的。

这又是关于覆盖和隐藏。我认为 - 但我可能错了 - 我都理解了。

以下代码的行为符合预期,两种方法都已隐藏。 method1 因为是私有方法,私有方法不能被覆盖,只能隐藏,method2 因为是静态,静态方法不能被覆盖,只能隐藏。

public class Child extends Parent { 
    public void method1(){System.out.println("child");}     
    public static void method2(){ System.out.println("static child");}  
}

class Parent{
    private void method1(){ System.out.println("parent");}      
    public static void method2(){ System.out.println("static parent");}

    public static void main(String[] args){
            Parent p = new Child();
            p.method1(); //prints out "parent"
            p.method2(); //prints out "static parent"
    }
}

如果我阅读它的规格说明:

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.3.3

可以将方法声明为 final 以防止子类覆盖 或隐藏它。

如果我将 Parent 类中的 method1 更改为“final”

private final void method1(){ System.out.println("parent");}

一切正常。 编辑开始:我预计会出现编译器错误,说最终方法无法隐藏,但这并没有发生。 :编辑结束

问题 1:这是否意味着只能隐藏静态方法?在我正在阅读的书(OCA 学习指南,Jeanne Boyarsky 和 ​​Scott Selikoff 第 252 页)中,他们清楚地说隐藏了一个私有方法。

然后我将Parent类中的method2改为

public final static void method2(){ System.out.println("static parent");}

现在编译器确实抱怨,错误说“孩子不能覆盖 method2()”,这很令人困惑,因为我以为我试图隐藏一个方法。

问题二:不应该是“Child cannot hide method2()”吗?

编辑开始:我很清楚这里没有覆盖,但正如提到的规范指出的那样:修饰符 final 防止方法被覆盖或隐藏,这就是我把它放在标题中的原因。 :编辑结束

【问题讨论】:

  • 你的例子有点混乱,因为method2是在method1之前定义的。为了可读性,您可能需要重新构建:a)首先定义方法 1,然后定义方法 2 和 b)首先定义类 Parent,然后定义类 Child,最后定义一些包含 main 方法的公共类作为测试框架。
  • 现在我真正的问题是:“一切正常”是什么意思?请说明您的预期和发生了什么。在覆盖最终方法时,我会期望出现编译器错误 - 你得到那个错误了吗?还是编译器通过了它?你看到被覆盖方法的打印输出了吗?
  • Oracle 教程强烈暗示您不能覆盖static 方法,只能隐藏它:docs.oracle.com/javase/tutorial/java/IandI/override.html
  • @penguineer:我改变了方法的顺序,但我保持了类的顺序。因为父类中的 method1 是私有的,所以我不会帮助创建一个包含主要方法的公共类。为了测试最终的修饰符,我需要以这种方式构造它。
  • @Victor Sorokin/penguineer:这里没有发生压倒一切的事情。我编辑了我的帖子以提及这一点。

标签: java methods overriding final method-hiding


【解决方案1】:

问题 1

问题 1:这是否意味着只能隐藏静态方法?

Parent.method1()Child 中不可见,也不被Child 继承,仅仅因为它是private。所以Child.method1() 没有覆盖或隐藏Parent.method1(),它只是在Child 中创建了一个具有相同名称、参数和返回类型的新方法。

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.3:

请注意,在这些术语的技术意义上,不能隐藏或覆盖私有方法。这意味着子类可以在其父类中声明与私有方法具有相同签名的方法,并且不要求此类方法的返回类型或 throws 子句与私有方法中的私有方法有任何关系。超类。

问题 2

问题二:不应该是“Child cannot hide method2()”吗?

是的,你是对的。它应该是“隐藏”。根据 JLS (http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.2),

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

“隐藏”是static 方法对static 方法所做的。 “覆盖”是实例方法对实例方法所做的事情。两者不能混用:static 方法不能覆盖或隐藏实例方法,实例方法不能覆盖或隐藏static 方法。

顺便说一句,我的 Eclipse 编译器给出了类似的错误消息:“无法覆盖 Parent 的最终方法”

【讨论】:

  • 私有方法和隐藏:我在提到的书中读到了这个,私有方法被隐藏了,并且由于编译器的行为,我认为它不能被隐藏(因为关于final 修饰符和隐藏方法)。我没有找到关于私有方法的部分(8.4.8.3)。谢谢,这对整个事情有所启发。
  • P.S. Eclipse 编译器:我知道,我在控制台和 Eclipse 中测试了整个东西。同样的错误。
【解决方案2】:

好吧,我对 java 很陌生,但我会尝试回答。

不同之处在于您使用不同的访问级别修饰符:您在父类的method1() 上使用私有,在子类的method1() 上使用公共。实际上,您并没有隐藏该方法,因为它不是同一种方法。 private 修饰符指定该成员只能在其自己的类中访问,因此,当您在 Child 类上声明 method1() 时,您正在使用一种新方法。即使 child 继承了 Parent 的所有方法(因为它扩展了它),但私有方法不会被继承。在method2() 的情况下,因为它被声明为public,它被Child 类继承并且可以被隐藏。

更多信息(取自oracle tutorials):

超类中的私有成员

子类不继承其父类的私有成员。但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法。

嵌套类可以访问其封闭类的所有私有成员——包括字段和方法。因此,子类继承的公共或受保护的嵌套类可以间接访问超类的所有私有成员。

编辑: 问题2:

您隐藏了一个静态方法,而不是最终方法。只有静态的可以像这里一样隐藏:

class SuperClass {
    static void display() {
        System.out.println("Super");
    }
}

class SubClass extends SuperClass {
    static void display() {
        System.out.println("Sub");
    }
}

public class Test {
    public static void main(String[] args) {
        // Prints "Super" in console
        SuperClass sup = new SubClass();
        sup.display();

        // Prints "Sub" in console
        SubClass sub = new SubClass();
        sub.display();
    }
}

您在方法声明中使用 final 关键字来指示该方法不能被子类覆盖。所以,如果你改变它,你就是在覆盖它,因此,编译器会说:

overridden method is static,final(注意final)。

编译器抱怨它,因为你不再隐藏它。当您声明它final 时,您正在覆盖它。如果您不在 Child 类上使用 static 修饰符,它将给您同样的错误,因为您将尝试覆盖它不再是 static 的内容。仅当静态方法隐藏另一个静态方法时才使用隐藏。如果你尝试:

  1. 非静态方法“隐藏”静态一:即覆盖。
  2. 最终方法“隐藏”静态方法:即覆盖。

在这些情况下,您不再尝试隐藏(因为隐藏仅用于静态),而是尝试覆盖。

【讨论】:

  • 没错。不过,我说的是编译器。如果您尝试:实例方法“隐藏”静态方法,编译器会认为您正在尝试覆盖它,因为您只能隐藏静态方法。这就是为什么编译器没有说“隐藏方法是静态的,最终的”。你看,编译器只知道静态可以隐藏静态。如果您尝试以“静态隐藏静态”以外的任何其他方式更改静态,编译器会认为您正在覆盖它。没有“隐藏的方法是静态的,最终的”错误,因为在我看来,隐藏只发生在静态上下文中。 :)
  • 哦,我的错。我用假设的方式说话。我是说:假设,假设您编写:实例方法“隐藏”静态方法。谢谢:)
猜你喜欢
  • 2011-10-15
  • 2015-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-15
  • 1970-01-01
相关资源
最近更新 更多