Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to make static reference to generic subclass (Java)

I have the following code:

class SuperClass {
    public static String getName() { return "super"; }
}

class SubClass extends SuperClass {
    public static String getName() { return "sub"; }
}

public class Dummy<T extends SuperClass> {
    public void print() {
        System.out.println("SuperClass: " + SuperClass.getName());
        System.out.println("SubClass: " + SubClass.getName());
        System.out.println("T: " + T.getName());
    }
    public static void main(String[] args) {
        new Dummy<SubClass>().print();
    }
}

This code outputs the following:

SuperClass: super
SubClass: sub
T: super

My question is: Why doesn't T.getName() return the value of SubClass.getName()? After all, I specified that T == SubClass. Or are static function calls invalid for generic references?

Thanks a lot in advance!

like image 616
marius Avatar asked Mar 24 '09 12:03

marius


2 Answers

This isn't just an issue about generics.

If you say:

SuperClass obj = new SubClass();
System.out.println(obj.getName());

you will also get "super". There are no "polymorphic" static methods.

In your case, all the compiler knows about T is that it extends SuperClass, so it will call SuperClass.getName().

like image 139
Simon Nickerson Avatar answered Oct 22 '22 17:10

Simon Nickerson


Unlike C++ templates, Java generics work by type erasure, so it only generates one class for all values of T, and translates all references to type T in this class to the super type of T, in this case SuperClass, then uses virtual dispatch to provide the variance for calls to object methods, and static dispatch to calls to static methods.

So when you do Dummy<SubClass>.print(), the compiler does not make a global replace of T with SubClass in Dummy. All the compiler does is check that uses of T as an argument or return type in the methods of Dummy are SubClass. There's no change to any code inside Dummy, so the same SuperClass static method gets called whatever T is.

If you want different behaviour in a generic class depending on the parameterised type, you have pass an object of that type in and use a virtual method, or pass in the class for the type and use reflection.

like image 32
Pete Kirkham Avatar answered Oct 22 '22 17:10

Pete Kirkham