In my opinion, the question is very interesting, it addresses several distinct issues and deserves more than one answer, although that one might be perfectly correct.
why do i need the in front of the SomeClass [Otherwise] there will be an ... error ... Cannot make a static reference to the non-static type T
The usage of static members, methods and fields, in a generic class has certain restrictions, see a section "Cannot Declare Static Fields Whose Types are Type Parameters". Although the section discusses fields, not methods, one could extend the reasoning to the methods as well. Indeed, if we agree that the declaration
private static T foo = null;
makes no sense because the compiler couldn't create an instance-independent variable foo
as the generic class could be parameterized with any type (Remember that Java Generic is not C++ Template, and due to the type erasure of the former there is one and only one (per a class loader) instance of a generic class in a runtime), then why something like
public static T get() {
return null;
}
should make more sense?
Second, when you declare generic type T
in your SomeClass
and then in newInstance
method, you in fact hide the first T
with the second one, and both are unrelated to each other. The type hiding is more obvious for non-static types. In the example
class Foo<T> {
<T> T get(){ // a warning "The type parameter T is hiding the type T"
return null;
}
}
the second T
, declared in a method, hides the first one, declared for the class, and that's where you receive a warning The type parameter T is hiding the type T
. To eliminate the warning, you have to replace T
in the method with another type variable, e.g. Z
, so that distinction between the two becomes obvious.
class Foo<T> {
<Z> Z get(){ // no warning, T and Z are different type variables
return null;
}
}
In a case of static method, the compiler does not issue a warning (probably because it thinks that for static things the hiding is assumed?), but the type hiding exists in this case as well. In the example you brought you managed to successfully cheat the Java Generic machinery (congrats :) ), but if we imagine the following scenario (I slightly refactored the semantic of your example to, let say, more traditional one)
static class Factory <T extends Number> {
private T t;
public static <T> T getInstance(){
return null;
}
public T get(){
return t;
}
}
, the both lines will compile
Number n1 = longFactory.get();
Number n2 = Factory.getInstance();
, but you lose type safety on the second, so that the line
String s1 = longFactory.get(); // fails to compile with "Type mismatch: cannot convert from Long to String" error message
fails, which is perfectly fine, but the line
String s2 = longFactory.getInstance(); // compiles only with a warning "static method should be accessed in a static way"
which is not fine and is not what you'd expect if you miss the point of type parameter hiding.
(Under the hood, T longFactory.get()
type-erases to Number longFactory.get()
, while static <T> T getInstance()
type-erases to static Object getInstance()
, e.g.
System.out.println(Factory.class.getMethod("getInstance").getReturnType().getSimpleName()); // prints "Object"
System.out.println(Factory.class.getMethod("get").getReturnType().getSimpleName()); // prints "Number"
but Type Erasure is another story)