Java - 隐藏覆盖和修饰符 final



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

同样,这是关于覆盖和隐藏。我想 - 但我可能是错的 - 我理解两者。

以下代码的行为符合预期,这两个方法都已隐藏。 方法1,因为它是私有

方法,私有方法不能被覆盖只能隐藏,方法2因为它是静态的,静态方法不能被覆盖,它们只能被隐藏。
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,以防止子类重写 或隐藏它。

如果我将父类中的方法 1 更改为"最终">

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

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

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

然后我将父类中的方法 2 更改为

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

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

问题2:不应该是"孩子不能隐藏方法2(("吗?

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

问题 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:

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

问题2

问题2:不应该是"孩子不能隐藏方法2(("吗?

是的,你是对的。它应该是"隐藏"的。根据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 编译器给出了类似的错误消息:"无法覆盖父级的最终方法">

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

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

更多关于它的信息(取自预言机教程(:

超类中的私有成员

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

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

编辑:问题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. 最后一种方法"隐藏"静态方法:即覆盖。

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

最新更新