English 中文(简体)
Behaviour of final static method
原标题:

I have been playing around with modifiers with static method and came across a weird behaviour.

As we know, static methods cannot be overridden, as they are associated with class rather than instance.

So if I have the below snippet, it compiles fine

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

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

But if I include final modifier to static method in class A, then compilation fails ts() in B cannot override ts() in A; overridden method is static final.

Why is this happening when static method cannot be overridden at all?

最佳回答

Static methods cannot be overridden but they can be hidden. The ts() method of B is not overriding(not subject to polymorphism) the ts() of A but it will hide it. If you call ts() in B (NOT A.ts() or B.ts() ... just ts()), the one of B will be called and not A. Since this is not subjected to polymorphism, the call ts() in A will never be redirected to the one in B.

The keyword final will disable the method from being hidden. So they cannot be hidden and an attempt to do so will result in a compiler error.

问题回答

static methods cannot be overriden

This is not exactly true. The example code really means that the method ts in B hides the method ts in A. So its not exactly overriding. Over on Javaranch there is a nice explanation.

Static methods belong to the class, not the instance.

A.ts() and B.ts() are always going to be separate methods.

The real problem is that Java lets you call static methods on an instance object. Static methods with the same signature from the parent class are hidden when called from an instance of the subclass. However, you can t override/hide final methods.

You would think the error message would use the word hidden instead of overridden...

You might find yourself in the position to think about making a static method final, considering the following:

Having the following classes:

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

Now the correct way to call these methods would be

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

which would result in AB but you could also call the methods on instances:

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

which would result in AB as well.

Now consider the following:

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

that would print A. That might surprise you since you are actually having an object of class B. But since you re calling it from a reference of type A, it will call A.ts(). You could print B with the following code:

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

In both cases the object you have is actually from class B. But depending on the pointer that points to the object, you will call method from A or from B.

Now let s say you are the developer of class A and you want to allow sub-classing. But you really want method ts(), whenever called, even from a subclass, that is does what you want it to do and not to be hidden by a subclass version. Then you could make it final and prevent it from being hidden in the subclass. And you can be sure that the following code will call the method from your class A:

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

Ok, admittetly that is somehow constructed, but it might make sense for some cases.

You should not call static methods on instances but directly on the classes - then you won t have that problem. Also IntelliJ IDEA for example will show you a warning, if you call a static method on an instance and as well if you make a static method final.

The ts() method in B is not overriding the ts() method in A, it simply is another method. The B class does not see the ts() method in A since it is static, therefore it can declare its own method called ts().

However, if the method is final, then the compiler will pick up that there is a ts() method in A that should not be overridden in B.

I think the compilation error was quite misleading here. It should not have said "overridden method is static final.", but it should instead have said "overridden method is final.". The static modifier is irrelevant here.

A static method can t be overridden in Java, unlike non-static methods. But they are inherited like static and non-static data members. That is why a non-static method with the same name can t be created in the parent class

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
    }
}

The final keyword ensures that the specific method body be run everytime a call to the method. Now if a static method is created in the child class with the same name and a call to the method is made, the method in the subclass gets executed which should not be the case if final is prefixed before the static method name in the parent class. Hence final keyword restricts the creation of method with the same name in the child class.

Static methods are "hidden" in inherited classes and cannot be overridden "non-statically" i.e. they cannot be overridden in a "polymorphism" sense. But they can be overridden "statically".

Static final methods are not allowed to be overridden even "statically".

The following example illustrates this -

App.java -

public class App {
    public static void main(String[] args) {
        Base.fun1();
        Base.fun2();
        Derived1.fun1();
        Derived1.fun2();
        Derived2.fun1();
        Derived2.fun2();
    }
}

Base.java -

public abstract class Base {

    protected static void fun1() {
        System.out.println("Static fun1() called in Base");
    }

    protected static final void fun2() {
        System.out.println("Static final fun2() called in Base");
    }

}

Derived1.java -

public class Derived1 extends Base {

    protected static void fun1() {
        System.out.println("Static fun1() called in Derived1");
    }
    
    //Not allowed to override final method
    /*
    protected static final void fun2() {
        System.out.println("Static final fun2() called in Derived1");
    }
    */
}

Derived2.java -

public class Derived2 extends Base {

    protected static void fun1() {
        System.out.println("Static fun1() called in Derived2");
    }
    
    //Not allowed to override final method
    /*
    protected static final void fun2() {
        System.out.println("Static final fun2() called in Derived2");
    }
    */
}

Output -

Static fun1() called in Base
Static final fun2() called in Base
Static fun1() called in Derived1
Static final fun2() called in Base
Static fun1() called in Derived2
Static final fun2() called in Base




相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签