最终静态方法的行为

时间:2009-11-16 17:43:04

标签: java methods static final

我一直在玩静态方法的修饰符,并且遇到了一种奇怪的行为。

我们知道,静态方法不能被覆盖,因为它们与类而不是实例相关联。

因此,如果我有以下代码段,则编译良好

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}

但是如果我在A类中将final修饰符包含到静态方法中,则编译失败 B中的 ts()不能覆盖A中的ts();重写方法是静态最终

为什么在无法覆盖静态方法时会发生这种情况?

7 个答案:

答案 0 :(得分:152)

无法覆盖静态方法,但可以隐藏它们。 B的ts()方法不会覆盖(不受多态性)A的ts(),但它会隐藏它。如果您在B中呼叫ts()(不是A.ts()B.ts()只是ts()),则会调用B中的一个而不是A.因为这不会受到影响对于多态,A中的调用ts()永远不会被重定向到B中的调用。

关键字final将禁止隐藏该方法。所以它们无法隐藏,尝试这样做会导致编译错误。

希望这有帮助。

答案 1 :(得分:12)

  

静态方法无法覆盖

这不完全正确。示例代码实际上意味着B中的方法ts隐藏了A中的方法ts。因此它不完全覆盖。在Javaranch上有一个很好的解释。

答案 2 :(得分:10)

静态方法属于类,而不属于实例。

A.ts()B.ts()始终是单独的方法。

真正的问题是Java允许您在实例对象上调用静态方法。当从子类的实例调用时,具有来自父类的相同签名的静态方法是hidden。但是,您无法覆盖/隐藏final methods

您会认为错误消息会使用隐藏字而不是覆盖...

答案 3 :(得分:5)

考虑到以下因素,您可能会发现自己可以考虑制作静态方法:

拥有以下课程:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

现在'正确'调用这些方法的方法是

A.ts();
B.ts();

这将导致AB,但您也可以调用实例上的方法:

A a = new A();
a.ts();
B b = new B();
b.ts();

也会导致AB

现在考虑以下事项:

A a = new B();
a.ts();

会打印A。这可能会让你感到惊讶,因为你实际上有一个类B的对象。但是,由于您是从A类型的引用中调用它,因此会调用A.ts()。您可以使用以下代码打印B

A a = new B();
((B)a).ts();

在这两种情况下,您拥有的对象实际上来自班级B。但是,根据指向对象的指针,您将从AB调用方法。

现在让我们假设您是班级A的开发人员,并且您希望允许进行子类化。但是你真的想要方法ts(),无论什么时候被调用,甚至从子类,你做它想做的事情,而不是被子类版本隐藏。然后你可以使它final并防止它隐藏在子类中。并且您可以确保以下代码将从您的班级A调用该方法:

B b = new B();
b.ts();

好的,承认这是以某种方式构建的,但对某些情况可能有意义。

你不应该在实例上调用静态方法,而是直接在类上调用 - 然后你就不会遇到这个问题。例如,如果你在一个实例上调用一个静态方法,那么IntelliJ IDEA会向你显示一个警告,如果你将一个静态方法调用为最终的话。

答案 4 :(得分:1)

我认为编译错误在这里有误导性。它不应该说“被覆盖的方法是静态最终的。”,但它应该说“被覆盖的方法是最终的。”。静态修饰符在这里无关紧要。

答案 5 :(得分:0)

B中的ts()方法没有覆盖A中的ts()方法,它只是另一种方法。 B类在A中看不到ts()方法,因为它是静态的,因此它可以声明自己的方法ts()。

但是,如果方法是最终的,那么编译器会发现在A中有一个不应该在B中覆盖的ts()方法。

答案 6 :(得分:0)

与非静态方法不同,静态方法在Java中不能被覆盖。 但是它们像静态和非静态数据成员一样被继承。这就是为什么不能在父类中创建具有相同名称的非静态方法的原因

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

final关键字可确保每次调用方法时都运行特定的方法主体。 现在,如果在子类中创建了具有相同名称的静态方法并对其进行了调用,则子类中的方法将被执行,如果final在父类中的静态方法名称之前添加前缀,则情况并非如此。因此,final关键字限制了子类中具有相同名称的方法的创建。