我正在尝试创建一个处理可比数据的类。我简化为最简单的代码,当我尝试实例化类时会出错。我得到了一些编译警告(未经检查的强制转换),但是当我运行此程序时,它会引发一个转发异常。我确实看过关于这个主题的一些其他问题,但没有发现有用的东西。
public class GD<Item extends Comparable<Item>> {
private Item[] data;
private final int MAX_SIZE = 200;
public GD() {
data = (Item[]) new Object[MAX_SIZE];
}
public static void main(String[] args) {
GD<String> g = new GD<String>();
}
}
答案 0 :(得分:2)
这很简单:Object
未实施Comparable<Object>
,但强制执行Item extends Comparable<Item>
。因此,您无法将Object[]
投射到Item[]
。
为了避免创建泛型类型Item
的数组的问题,我们可以看一下Java的ArrayList
实现。此处,支持数组的类型为Object
,只能通过mutator methods访问:
private Object[] data; // Make the backing array private, access only via mutator methods
public void add(Item i)
{
int idx = ... // calculate next free index somehow
this.data[idx] = i;
}
public Index get(int idx) {
return ((Item) (this.data[idx]));
}
由于您只允许插入Item
,因此您只能返回Item
,因此您永远不会拥有ClassCastException
。
对您的代码的一些评论:通常,使用T
,U
,S
作为类型参数。如果您使用Item
之类的内容,可能会将类型参数与实际类混淆。
答案 1 :(得分:1)
问题在于:
data = (Item[]) new Object[MAX_SIZE];
您正在实例化一个Object
数组,然后您尝试将其强制转换为Item
数组,这会引发异常,因为Object
不会扩展您的Item
class,因为它没有实现Comparable
。你想要的是:
data = new Item[MAX_SIZE];
但是你不能这样做因为Item
是一般类型。如果要动态创建此类型的对象(或对象数组),则需要将Class
对象传递给GD类的构造函数:
import java.lang.reflect.Array;
public class GD<Item extends Comparable<Item>> {
private Item[] data;
private final int MAX_SIZE = 200;
public GD(Class<Item> clazz) {
data = (Item[]) Array.newInstance(clazz, MAX_SIZE);
}
public static void main(String[] args) {
GD<String> g = new GD<String>(String.class);
}
}
答案 2 :(得分:1)
强制转换(Item[])
不会针对Item[]
检查对象的运行时类型,因为Item
在运行时是未知的;相反,它会检查Item[]
的删除,Comparable[]
(因为Comparable
是Item
的删除)。实际运行时类为Object[]
的对象不是Comparable[]
的实例,因此会导致ClassCastException
。这就是为什么简单地做
data = (Item[]) new Comparable[MAX_SIZE];
将使例外消失。
所以有两种方法可以解决这个问题:
理论类型&#34;安全&#34;方法,即使用固定的非特定数组类型,如Object[]
或Comparable[]
作为data
变量的编译时类型。这样,您可以创建具有相同运行时类型的数组对象,并安全地将其分配给变量,而不会出现不安全的强制转换。但是,当您需要从数组中取出某些内容并将其作为泛型类型返回时,您必须进行显式(未经检查)的强制转换:
public class GD<Item extends Comparable<Item>> {
private Object[] data;
private final int MAX_SIZE = 200;
public GD() {
data = new Object[MAX_SIZE];
}
public Item get(int index) {
return (Item)data.get(index);
}
}
或者,您可以将data
保留为Item[]
,方法是在创建new Comparable[]
时进行不安全的转换。请注意,这在理论上是无效的强制转换,因为数组的实际运行时类是Comparable[]
,它通常不是Item[]
的实例。但是,在此课程中,Item
被删除为Comparable
,只要data
为Item[]
的声明未被曝光,此谎言就不会造成任何问题课堂外(例如,如果data
是公开的,或者如果有getArray()
方法直接将data
作为Item[]
返回,那么那就不好了) 。这种方式的优点是,当您从阵列中获取某些内容时,您不必进行投射。缺点是程序员要小心不要将这种谎言暴露在外面。
public class GD<Item extends Comparable<Item>> {
private Item[] data;
private final int MAX_SIZE = 200;
public GD() {
data = (Item[])new Comparable[MAX_SIZE];
}
public Item get(int index) {
return data.get(index);
}
}