简体   繁体   English

尝试创建定制类的通用数组时发生Java转换错误

[英]Java cast error trying to create a generic array of custom made class

This is what I'm trying to do: 这就是我想要做的:

import java.lang.reflect.*;

class exampleOuter <T extends Number>
{
    private exampleInner<T>[] elements;

    public exampleOuter(Class<T> type, int size)
    {
        elements = (exampleInner<T>[]) Array.newInstance(type, size);
    }
}

I was told that if I wanted to create generic arrays of type T, I should use 有人告诉我,如果我想创建类型T的通用数组,应该使用

elements = (T[]) Array.newInstance(type,size);

So I tried to extend that to my custom class and got a ClassCastException (Ljava.lang.Double; cannot be cast to L mypackagename .exampleInner; I'm declaring the class in main like this: 所以我试图将其扩展到我的自定义类,并得到ClassCastException(Ljava.lang.Double;无法转换为L mypackagename .exampleInner;我在main中声明该类,如下所示:

exampleOuter<Double> test = new exampleOuter(Double.class,15);

I can declare the inner class just fine and I can also declare arrays that aren't generic of the innerClass, so I imagine it's something in the constructor of the outerClass. 我可以声明内部类很好,也可以声明不是innerClass通用的数组,因此我想它是在externalClass的构造函数中。 Any ideas? 有任何想法吗?

EDIT: I understand what the problem is. 编辑:我明白是什么问题。 When I create a new instance of the array, I create an array of doubles, not of exampleInner. 创建数组的新实例时,将创建一个double数组,而不是exampleInner数组。 I think. 我认为。 If that's right, I need to find a way to create an array of exampleInner while passing just Double.class to the function. 如果是的话,我需要找到一种方法来创建exampleInner数组,同时将Double.class传递给函数。

EDIT 2: I realize generic arrays are not typesafe, but I have to use them anyway because my teacher demands that we use them. 编辑2:我意识到泛型数组不是类型安全的,但是无论如何我都必须使用它们,因为我的老师要求我们使用它们。

EDIT 3: I was told that to use generic arrays I had to allocate them that way, and to do so I need reflections, I think. 编辑3:有人告诉我,要使用通用数组,必须以这种方式分配它们,为此,我需要反思。 The compiler tells me the class is using unsafe or unchecked operations, but I have to use generic arrays and that's the way I know to do it. 编译器告诉我该类正在使用不安全或未经检查的操作,但是我必须使用通用数组,这就是我所知道的方式。 If there's a better way I'll change the code. 如果有更好的方法,我将更改代码。

This is the solution I've come up with: 这是我想出的解决方案:

public exampleOuter(Class<T> type, int size)
{
    innerClass<T> aux = new innerClass<T>(); 
    elements = (exampleInner<T>[]) Array.newInstance(aux.getClass(), size);
}

I thought this would also work: 我认为这也会起作用:

elements = (exampleInner<T>[]) Array.newInstance(innerClass<T>.class, size);

But it doesn't, probably because of the way generics are implemented in Java (type erasure and all that). 但这不是,可能是由于Java中泛型的实现方式(类型擦除等)。

The problem with the first approach is that I'm forced to create a new object and instantiate despite not really needing it. 第一种方法的问题是,尽管我确实不需要它,但我还是不得不创建一个新对象并实例化它。 Plus, it makes the code more bloated imo. 另外,它使代码更加膨胀。

EDIT: The second approach wasn't working because I was using innerClass<T>.class instead of innerClass.class . 编辑:第二种方法不起作用,因为我使用的是innerClass<T>.class而不是innerClass.class Thanks for the suggestion, I'll use it now. 感谢您的建议,我现在将使用它。

You are creating, for some specific T , an object of type T[] and assigning it to a field of type exampleInner<T>[] which is going to be an error. 您正在为某些特定的T创建一个T[]类型的对象,并将其分配给exampleInner<T>[]类型的字段,这将是一个错误。

For T extends Number : the erase type of T[] is Number[] ; 对于T extends NumberT[]的擦除类型为Number[] for the erased type of exampleInner<T>[] is exampleInner[] . 对于exampleInner<T>[]的擦除类型为exampleInner[] But the compiler warnings should have indicated that you were doing something wrong anyway. 但是编译器警告应该已经表明您在做任何错误的事情。

But you almost certainly do not need reflection, so don't use it. 但是您几乎可以肯定不需要反射,所以不要使用它。

T extends Number and you're trying to cast it to an exampleInner, which I doubt is in the right place in the Number hierarchy. T扩展了Number,您正在尝试将其强制转换为exampleInner,我怀疑它在Number层次结构中的正确位置。

Try it without your exampleInner. 在没有您的exampleInner的情况下尝试。 Or try passing exampleInner as the type argument to the exampleOuter constructor. 或尝试将exampleInner作为类型参数传递给exampleOuter构造函数。

You don't have "generic array creation" here. 您在这里没有“通用数组创建”。 The component type of the array is "exampleInner" (well, it should be exampleInner, but array component types must be "reified types", so it can't store the at runtime.), which is known at compile time. 数组的组件类型是“ exampleInner”(好,应该是exampleInner,但是数组组件类型必须是“ reified类型”,因此它不能在运行时存储。),这在编译时是已知的。 So you don't need to pass in the Double.class parameter. 因此,您无需传递Double.class参数。

What you really need to do is create an array of a parameterized type. 您真正需要做的是创建一个参数化类型的数组。 One way to do this is to create an array of the raw type, and cast it to the array-of-parameterized type. 一种方法是创建原始类型的数组,并将其转换为参数化类型的数组。 This will allow you to use the array as you normally would and get the benefits of the generics of not having to cast when you get stuff out and stuff. 这将使您能够像往常一样使用数组,并获得在放出东西时不必强制转换的泛型的好处。

Technically, this is an unchecked cast, because it could in theory cause unexpected problems later because it can't prevent you from putting the wrong type of objects in the array. 从技术上讲,这是未经检查的强制转换,因为理论上它以后可能会导致意外问题,因为它不能防止您将错误类型的对象放入数组中。 But since this is a private variable in your class, and I'm assuming that you only manipulate it within your class, and if you trust your own code to use it correctly, then it will work. 但是由于这是您类中的一个私有变量,并且我假设您仅在类中对其进行操作,并且如果您信任自己的代码可以正确使用它,那么它将起作用。

import java.lang.reflect.*;

class exampleOuter <T extends Number>
{
    private exampleInner<T>[] elements;

    @SuppressWarnings("unchecked")
    public exampleOuter(int size)
    {
        elements = (exampleInner<T>[]) new exampleInner[size];
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM