5

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

再次是关于覆盖和隐藏。我认为——但我可能错了——我都理解。

以下代码按预期运行,两种方法都已隐藏。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 以防止子类覆盖或隐藏它。

如果我将父类中的 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");}

现在编译器确实抱怨了,错误说“Child cannot override method2()”这很令人困惑,因为我以为我试图隐藏一个方法。

问题2:不应该是“孩子不能隐藏method2()”吗?

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

4

2 回答 2

8

问题 1

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

Parent.method1()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

问题2:不应该是“孩子不能隐藏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 编译器给出了类似的错误消息:“无法覆盖父级的最终方法”

于 2016-02-03T14:13:42.677 回答
2

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

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

有关它的更多信息(取自oracle 教程):

超类中的私有成员

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

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

编辑:问题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. 最终方法“隐藏”静态方法:即覆盖。

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

于 2016-02-03T14:28:01.877 回答