Java泛型类转换异常

时间:2015-07-01 23:28:27

标签: java generics comparable

我正在尝试创建一个处理可比数据的类。我简化为最简单的代码,当我尝试实例化类时会出错。我得到了一些编译警告(未经检查的强制转换),但是当我运行此程序时,它会引发一个转发异常。我确实看过关于这个主题的一些其他问题,但没有发现有用的东西。

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>();
   }
}

3 个答案:

答案 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

对您的代码的一些评论:通常,使用TUS作为类型参数。如果您使用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[](因为ComparableItem的删除)。实际运行时类为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,只要dataItem[]的声明未被曝光,此谎言就不会造成任何问题课堂外(例如,如果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);
       }
    }