Java - 隐藏重写和修饰符 final

Java - Hiding Overriding and the modifier final

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

同样是关于覆盖和隐藏。我想 - 但我可能错了 - 我都理解。

以下代码按预期运行,两种方法均已隐藏。 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

A method can be declared final to prevent subclasses from overriding or hiding it.

如果我将 Parent class 中的 method1 更改为 "final"

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

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

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

然后我将 Parent class 中的 method2 更改为

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

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

问题 2:不应该是 "Child cannot hide method2()" 吗?

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

问题 1

Question no 1: does that mean only static methods can be hidden?

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

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

Note that a private method cannot be hidden or overridden in the technical sense of those terms. This means that a subclass can declare a method with the same signature as a private method in one of its superclasses, and there is no requirement that the return type or throws clause of such a method bear any relationship to those of the private method in the superclass.

问题 2

Question no 2: Shouldn't it be "Child cannot hide method2()"?

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

If a class C declares or inherits a static method m, then m is said to hide any method m', where the signature of m is a subsignature (§8.4.2) of the signature of m', in the superclasses and superinterfaces of C that would otherwise be accessible to code in C.

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

顺便说一句,我的 Eclipse 编译器给出了类似的错误消息:"Cannot override the final method from Parent"

嗯,我对 java 很陌生,但我会尽力回答。

区别在于您使用不同的访问级别修饰符:您在 method1() of Parent class 和 public 上使用 private method1() Child class。事实上,你并没有隐藏这个方法,因为它不是同一个方法。 private 修饰符指定成员只能在其自己的 class 中访问,因此,当您在 Child class 上声明 method1() 时,您正在使用新方法。尽管 child 继承了 Parent 的所有方法(因为它扩展了它),私有方法不会被继承。在 method2() 的情况下,因为它被声明为 public,它被 Child class 继承并且可以被隐藏。

更多信息(摘自oracle tutorials):

Private Members in a Superclass

A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.

A nested class has access to all the private members of its enclosing class—both fields and methods. Therefore, a public or protected nested class inherited by a subclass has indirect access to all of the private members of the superclass.

已编辑: 问题 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 关键字来指示该方法不能被子classes 覆盖。所以,如果你改变它,你就会覆盖它,因此,编译器说:

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

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

  1. 非静态方法"hides"静态方法一:也就是override。
  2. final方法"hides"静态一:也就是override。

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