我在类中定义了一个方法:
public void setCollection(Collection<MyClass>);
并在另一个班级
public void setCollection(Collection<OtherClass>);
(实际上,很多类似的课程)
所有都在具有相同超类的类中,并且我在支持类中有一个方法,我想调用此方法并使用正确类类型的项设置它。现在,我可以通过执行
来设置集合Method setter = ...;
Class<?> paramClass = setter.getParameterTypes()[0]; // Is Collection in this case
if(paramClass.equals(Collection.class)) {
HashSet col = new HashSet();
// fill the set with something
setter.invoke(this, col);
}
但是如何确定此集合中的对象应该属于哪个类?
干杯
的Nik
答案 0 :(得分:9)
Method.getGenericParameterTypes();
返回参数接受的Types数组。复杂性从那里呈指数增长。
在您的具体情况下,这可行:
Method m = Something.class.getMethod("setCollection", Collection.class);
Class<?> parameter = (Class<?>) ((ParameterizedType) m.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
但是那里存在很多潜在的问题,具体取决于参数的声明方式。如果它像你的例子一样简单,那很好。如果没有,那么在getGenericParameterTypes()方法和getActualTypeArguments()方法中都有一些类型需要考虑。它变得非常毛茸茸,非常快。
答案 1 :(得分:2)
我会考虑将setCollection方法移到他们自己的类中,然后做更像这样的事情(你可以改变它来一次创建整个集合,而不是一次作为一个元素)。
这消除了反射并确保它在编译时是类型安全的。我可能会误解你要做的是什么,但我想我明白了。 “init”方法将是辅助方法(至少如果我理解你的目标是什么)。
public class Main
{
public static void main(String[] args)
{
List<Car> car;
List<Bar> bar;
car = new ArrayList<Car>();
bar = new ArrayList<Bar>();
init(car, new CarCreator());
init(bar, new BarCreator());
}
private static <T> void init(final List<T> list,
final Creator<T> creator)
{
for(int i = 0; i < 10; i++)
{
final T instance;
instance = creator.newInstance(i);
list.add(instance);
}
}
}
interface Foo
{
}
class Bar implements Foo
{
}
class Car implements Foo
{
}
interface Creator<T>
{
T newInstance(int i);
}
class BarCreator
implements Creator<Bar>
{
public Bar newInstance(final int i)
{
return (new Bar());
}
}
class CarCreator
implements Creator<Car>
{
public Car newInstance(final int i)
{
return (new Car());
}
}
答案 2 :(得分:1)
Java使用类型擦除实现泛型。编译器仅将此类型信息用于安全检查,字节代码不包含有关泛型类型的任何信息。因此,运行时也不知道它,因此您无法通过反射来检索它。
您可以找到一些其他信息here。
<强>更新强>:
要纠正自己,请考虑以下方法:
public <T> String doSomething(T first, int second) {
return first.toString();
}
在字节代码中,这将具有以下签名(注意T类型):
<T:Ljava/lang/Object;>(TT;I)Ljava/lang/String
所以我上面所说的只有这个例外。
答案 3 :(得分:0)
你似乎已经知道了二传手。所以在我看来,在这种情况下,MyClass和OtherClass(不是集合,但是项目)共享一些类似的界面。 在这种情况下,您实际上并不需要知道确切的类型。
答案 4 :(得分:0)
正如candiru已经解释的那样,'Collection Type'被删除了,在运行时它只是一个对象类型集合。
如果允许您将子类中的消息签名稍微更改为
public void setCollection(Collection<T> aCollection, Class<T> elementType);
然后您可以传递第二个参数来保存“集合类型”的信息,用法如下:
public void setCollection(Collection<MyClass> myClassCollection,
Class<MyClass> clazz);
并使用它:
Collection<MyClass> myClassCollection = new ArrayList<MyClassCollection>();
setCollection(myClassCollection, MyClass.class);
但另一方面 - 通常你不必关心它,因为类型在运行时被删除,你可以把任何类型的对象放在paramterized集合中,只要你没有被编译器捕获;)