Java 如何正确使用泛型类型的数组?
我有一个类,它根据消息的类将传入消息映射到匹配的读取器。所有消息类型都实现接口消息。读取器在mapper类中注册,说明它将能够处理哪些消息类型。这些信息需要以某种方式存储在消息读取器中,我的方法是从构造函数中设置一个Java 如何正确使用泛型类型的数组?,java,generics,Java,Generics,我有一个类,它根据消息的类将传入消息映射到匹配的读取器。所有消息类型都实现接口消息。读取器在mapper类中注册,说明它将能够处理哪些消息类型。这些信息需要以某种方式存储在消息读取器中,我的方法是从构造函数中设置一个私有final数组 现在,我似乎对泛型和/或数组有一些误解,我似乎无法理解,请参阅下面的代码。这是什么 public class HttpGetMessageReader implements IMessageReader { // gives a warning becau
私有final
数组
现在,我似乎对泛型和/或数组有一些误解,我似乎无法理解,请参阅下面的代码。这是什么
public class HttpGetMessageReader implements IMessageReader {
// gives a warning because the type parameter is missing
// also, I actually want to be more restrictive than that
//
// private final Class[] _rgAccepted;
// works here, but see below
private final Class<? extends IMessage>[] _rgAccepted;
public HttpGetMessageReader()
{
// works here, but see above
// this._rgAccepted = new Class[1];
// gives the error "Can't create a generic array of Class<? extends IMessage>"
this._rgAccepted = new Class<? extends IMessage>[1];
this._rgAccepted[0] = HttpGetMessage.class;
}
}
公共类HttpGetMessageReader实现IMessageReader{
//由于缺少类型参数,因此发出警告
//而且,我实际上想比这更严格一些
//
//私人最终课程[]接受;
//在这里工作,但请参见下文
Java不允许私有final类。有关详细信息,请参阅
要回答您的问题,只需使用(可能)而不是数组
更多解释请参见:
泛型不是协变的
虽然你可能会发现
将收藏视为一种艺术
对于数组的抽象,它们有一些
集合所具有的特殊属性
不是。Java语言中的数组是
协变的,也就是说如果
整数扩展了它所指定的数字
则不仅是一个整数
也是一个数字,但不允许使用整数[]
还有一个号码[]
,您可以
传递或分配一个整数[]
,其中
调用编号[]
。(更多信息)
形式上,如果Number
是超类型
如果是整数
,则数字[]
是一个
整数[]
的超类型
我认为泛型也是如此
还有类型--列表
是列表的超类型,并且
您可以传递一个列表
其中需要一个列表
。
不幸的是,这不起作用
对
事实证明这是一个很好的理由
这样不行:它会坏的
假设类型安全泛型
提供。想象一下你可以分配一个
列表
到列表
。
那么下面的代码将允许
你想把一些不是
整数
放入列表
:
List li=new ArrayList();
列表ln=li;//非法
增加(新浮动(3.1415));
因为ln是一个列表
,添加
一个浮点数
对它来说似乎是完全合法的。
但是如果ln的别名是li那么
这将违反类型安全承诺
隐含在李的定义中--
这是一个整数列表
这就是泛型类型不能被定义的原因
协变的
数组总是属于特定的类型,这与泛型之前的集合不同
而不是
Class<? extends IMessage>[] _rgAccepted;
泛型不包括在内
那么什么是“正确的”(或者至少是普通的)方法呢
@SuppressWarnings(value=“unchecked”)
公共T[]的(类componentType,整型大小){
return(T[])Array.newInstance(componentType,size);
}
公共演示(){
整数[]a=of(Integer.class,10);
System.out.println(Arrays.toString(a));
}
克莱特斯说的没错。泛型类型参数的通常强制不变性与Java数组的协变性之间存在普遍的不匹配
(一些背景:Variance指定类型在子类型方面如何相互关联。例如,由于泛型类型参数是不变的
收集IMHO
this.\u rgAccepted=(类这两行实际上并不相等。我确实希望传递类对象。然后,正如cletus所建议的,您将希望使用ArrayList(或另一个集合对象)而不是数组。类不是泛型类型,它是表示类元数据的类。(这让我想起了我曾经读过的一句话:“每个类对象的对象都有一个表示对象类的类对象”)类是泛型类型。更具体地说,它有一个类型参数,即它实际上被称为类。请看FAQ链接非常有用,谢谢。具有讽刺意味的是,根据我发现的一些文章,像ArrayList这样的集合似乎在幕后使用未经检查的类型转换,所以我可以只执行@SuppressWarnings(“未经检查”)我自己。是的,这是完全合理的。我试着对@SuppressWarnings的每一次使用进行评论,以便我以后理解其背后的原因。顺便说一句:仅出于编译时原因使用集合类型,在您可能确实需要运行时数组语义的情况下,似乎不是我的一般答案……在许多情况下,必须找到一个平衡静态类型安全性和性能运行时行为之间的差异(即使ArrayList相对于普通数组的成本很小),如果您不介意以Object[]而不是(可能是泛型的)组件类型的原始类型结束,请将新对象[size]强制转换为t[]将更快。Array.newInstance必须支付通常的反射成本。您不能分配对象[size]数组,然后将其用作T[].Array。newInstance(Foo.class,N)类似于malloc(sizeof(struct Foo)*N。return(T[])新对象[size];不能分配给整数[]它是一个java.lang.ClassCastException
Class<? extends IMessage>[] _rgAccepted;
IMessage[] _rgAccepted;
@SuppressWarnings(value="unchecked")
public <T> T[] of(Class<T> componentType, int size) {
return (T[]) Array.newInstance(componentType, size);
}
public demo() {
Integer[] a = of(Integer.class, 10);
System.out.println(Arrays.toString(a));
}
public static <T> T[] array(T...els){
return els;
}
void test(){
// warning here: Type safety : A generic array of Class is created for a varargs parameter
Class<? extends CharSequence>[] classes = array(String.class,CharSequence.class);
}
this._rgAccepted = (Class<? extends IMessage>[])new Class[1];