Java稍后使用泛型来设置数组的原始类型
我正在尝试用 Java 编写一些简单的数字代码,稍后可以在 float 和 double 之间进行选择。我的类的简化版本如下所示:
public class UniformGrid<T> {
public T[] data;
public UniformGrid(int arrayDim) {
data = new T[arrayDim];
}
}
这不起作用,我在尝试编译时遇到了通用数组创建
错误。谷歌搜索并阅读一些 SO 答案,我了解了 java.lang.reflect.Array 并尝试使用
data = (T[]) Array.newInstance(T.class, arrayDim);
Which 也不起作用,因为 T (可能)是原始类型。我的 Java 知识很生疏(尤其是在泛型方面),我想知道为什么 new 运算符不能与泛型数组类型一起使用。当然,我也对如何用 Java 解决这个问题感兴趣。
I am trying to write some simple numerical code in Java where one can choose between a float and double later. A simplified version of my class looks like the example below:
public class UniformGrid<T> {
public T[] data;
public UniformGrid(int arrayDim) {
data = new T[arrayDim];
}
}
This didn't work I got a generic array creation
error when trying to compile. Googling and reading some SO answers I learned about java.lang.reflect.Array
and tried to use
data = (T[]) Array.newInstance(T.class, arrayDim);
Which also didn't work, since T is (probably) a primitive type. My Java knowledge is quite rusty (especially when it comes to generics) and I would like to know why the new operator cannot be used with a generic array type. Also of course I am interested in how one would solve this problem in Java.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
由于类型擦除,您无法在 Java 中创建泛型数组。解决这个问题的最简单方法是使用
List
。但如果必须使用数组,则可以为数组使用Object[]
并确保仅将T
对象放入其中。 (这是 ArrayList 所采用的策略。)例如:
当然,您会从编译器收到未经检查的警告,但您可以抑制该警告。
You cannot create a generic array in Java because of type erasure. The easiest way to get around this would be to use a a
List<T>
. But if you must use an array, you can use anObject[]
for your array and ensure that onlyT
objects are put into it. (This is the strategyArrayList
takes.)Ex:
Of course you'll get an unchecked warning from your compiler, but you can suppress that.
创建数组时不能使用泛型,因为您在运行时不知道 T 是什么类型。这称为类型擦除。
解决方案很简单:使用
List;数据
。Generics can't be used when creating an array because you don't know at runtime what type T is. This is called type erasure.
The solution is simple: use
List<T> data
.抱歉,您必须采取另一种方法:
如果您确实需要这个,我会研究代码生成,也许作为自动构建的一部分。 (对源代码进行简单的搜索和替换应该能够将在双精度上运行的库转变为在浮点上运行的库。)
Sorry, you'll have to take another approach:
If you really need this, I'd look into code generation, perhaps as part of an automated build. (A simple search & replace on the source ought to be able to turn a library operating on double into a library operating on float.)
这是可能的,只要您使用
Float
和Double
而不是float
和double
,因为原始类型是Java 泛型中不允许。当然,这可能会很慢。而且,您将无法(安全地)允许公众直接访问该阵列。所以这个答案不是很有用,但理论上可能很有趣。无论如何,如何构造数组......这会给你一个警告,但这并不是直接需要担心的事情。它以这种特定的形式工作 - 它位于通用构造函数内,并且
data
是对此新构造的对象的唯一引用。 查看此页面。您不会能够以您喜欢的方式公开访问此数组对象。您需要在
UniformGrid
中设置方法来获取和设置对象。这样,编译器将确保类型安全,并且运行时不会给您带来任何问题。在这种情况下,
set
的接口将(在编译时)强制传递正确的类型。底层数组的类型是Object[]
,但这没关系,因为它可以采用任何引用类型 - 并且所有泛型类型在运行时实际上都是List
有趣的是吸气剂。编译器“知道”
data
的类型是T[]
,因此 getter 将干净地编译并承诺返回T
。因此,只要您将data
保持私有,并且仅通过get
和set
访问它,那么一切都会好起来的。一些示例代码位于 ideone 上。
正如您所希望的,
uf.insert(0, new Object())
和B o2= uf.get(0);
存在编译错误,但您不应该' t 将
data
成员公开。如果这样做,您可以编写并编译A via_array1 = uf.data[0];
。该行看起来应该没问题,但是您会遇到运行时异常:Ljava.lang.Object;无法转换为 [LA;
。简而言之,来代替。这个故事的寓意是:在任何语言(Java 或 C++)中,无论是否有泛型,都要对数组说不。 :-)
get
和set
接口提供了一个安全的接口。但是,如果您在使用数组时遇到了这么多麻烦,那么您应该使用 ArrayListThis is possible, as long as you use
Float
andDouble
instead offloat
anddouble
, as primitive types are not allowed in Java Generics. Of course, this will probably be quite slow. And, you won't be able to (safely) allow direct public access to the array. So this answer is not very useful, but it might be theoretically interesting. Anyway, how to construct the array ...This will give you a warning, but it's not directly anything to worry about. It works in this particular form - it's inside a generic constructor and
data
is the only reference to this newly constructed object. See this page about this.You will not be able to access this array object publicly in the way you might like. You'll need to set up methods in
UniformGrid<T>
to get and set objects. This way, the compiler will ensure type-safety and the runtime won't give you any problems.In this case, the interface to
set
will (at compile-time) enforce the correct type is passed. The underlying array is of typeObject[]
but that's OK as it can take any reference type - and all generic types are effectivelyList<Object>
or something like that at runtime anyway.The interesting bit is the getter. The compiler 'knows' that the type of
data
isT[]
and hence the getter will compile cleanly and promises to return aT
. So as long as you keep thedata
private and only access it throughget
andset
then everything will be fine.Some example code is on ideone.
As you would desire, there are compilation errors with
uf.insert(0, new Object())
andB o2= uf.get(0);
But you shouldn't make the
data
member public. If you did, you could write and compileA via_array1 = uf.data[0];
. That line looks like it should be OK, but you get a runtime exception:Ljava.lang.Object; cannot be cast to [LA;
.In short, the
get
andset
interface provide a safe interface. But if you go to this much trouble to use an array, you should just use anArrayList<T>
instead. Moral of the story: in any language (Java or C++), with generics or without generics, just say no to arrays. :-)Effective Java,第二版中的第 25 条讨论了这个问题:
Item 25 in Effective Java, 2nd Edition talks about this problem: