问题描述
我有一个泛型类工厂类,它有两个方法利用类的泛型T值,另一个只使用它自己的方法泛型定义。
Scratchpad.list 与 T 无关。
详细记录在:
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:
Data data = new GenericClassFactory<ClassMatchable>().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");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:
Data data = GenericClassFactory.newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");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:
public class Scratchpad<T> { List<String> list; public static void main(String[] args) { Scratchpad sp = new Scratchpad(); List<Integer> list = sp.list; } }And that's because sp.list is resolved as a List, not a List<String>, even though Scratchpad.list has nothing to do with T.
This is verbosely documented in the JLS, Section 4.8:
这篇关于Java类泛型和方法泛型冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!