Java - 隐藏覆盖和修改器最终

时间:2016-02-03 13:56:23

标签: java methods override final method-hiding

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

再一次,它是关于覆盖和隐藏的。我想 - 但我可能错了 - 我理解两者。

以下代码按预期运行,两种方法都已隐藏。 method1因为它是一个私有方法,私有方法只能被隐藏,方法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以防止子类重写   或隐藏它。

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

现在编译器确实抱怨,错误说" Child无法覆盖method2()"这很混乱,因为我以为我试图隐藏一个方法。

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

编辑开始:我很清楚这里没有重写,但正如上面提到的规范所指出的那样:修饰符final会阻止方法被覆盖或隐藏,这就是为什么我把它放在标题中。 :编辑结束

2 个答案:

答案 0 :(得分: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:不应该是“孩子不能隐藏方法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方法。

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

答案 1 :(得分:2)

嗯,我对java很新,但我会尝试回答。

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

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

  

超类中的私人会员

     

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

     

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

EDITED: 问题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. 最终方法"隐藏"静态的:即覆盖。
  3. 在这些情况下,您不再试图隐藏(因为隐藏仅用于静态),但您正试图覆盖。