I have a Generic Class Factory class that has two methods one utilizes the Class generic T value and the other only uses its own method generic definitions.
public class GenericClassFactory<T extends ClassMatchable> {
public <E, K> E newObject(ClassMatcher<E, K> matcher, K key, String packageName){...}
public <K> T newObject(K key, String packageName){...}
}
The method that utilizes the T generic works fine but when I want to use the other method that doesn’t care what the T generic is it won’t use the Generic E it will just return an Object and then I have to type cast it.
Data data = new GenericClassFactory().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");
This has compile errors because it wants me to typecast it to (Data). If I pass the GenericClassFactory a valid Class Generic it will work. Its like it doesn’t recognize method generics if you have a Class Generic defined but not used.
Data data = new GenericClassFactory<ClassMatchable>().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");
That works fine. But it’s dumb that I would have to define a class generic like that when it isn’t needed for my purposes. I could do this:
public class GenericClassFactory {
public <E, K> E newObject(ClassMatcher<E, K> matcher, K key, String packageName){...}
public <T extends ClassMatchable, K> T newObject(K key, String packageName){...}
}
But now my second method seems like its too broad or something…maybe not. I mean it will still give a compile error if the object you are assigning to the return type doesn’t implement ClassMatchable. Is that the way I should go? So that I don’t have to typecast?
That’s right, if you don’t type a class reference, then even generic methods that only use method type parameters will not be generified. It’s one of the weirder nuances of Java Generics. As you say, you can put in some arbitrary type for
T:But more likely this shouldn’t even be an instance method. Can’t it be a static method? If so you could just invoke it like this:
Edit
Note that this extends to all instance members, not just generic instance methods. Thus, there are simpler cases that demonstrate this odd nuance. This code compiles with only warnings:
And that’s because
sp.listis resolved as aList, not aList<String>, even thoughScratchpad.listhas nothing to do withT.This is verbosely documented in the JLS, Section 4.8: