java.lang.ClassCastException : [Ljava. lang.Comparable;不能转换到

标签 java

我的代码中出现以下异常: 线程“main”中的异常 java.lang.ClassCastException: [Ljava.lang.Comparable;不能转换为 [LElement; 在以下调用中:

Element<K,V>[] heap = (Element<K,V>[]) new Comparable[size]; 

其中元素定义如下:

class Element<K, V> implements Comparable<Element<K, V>>{
    long timeStamp;
    K key;
    V val;
    @Override
    public int compareTo(Element<K, V> o) {
    return new Long(timeStamp).compareTo(o.timeStamp);
}
Element(long ts, K key, V val){
    this.timeStamp = ts;
    this.key = key;
    this.val = val;
    }

}

非常感谢任何帮助!

最佳答案

发生这种情况是因为 Java 类型删除。 要回答这个问题,我需要解释一下无界通配符、有界通配符和类型删除。如果您熟悉任何部分,请随意跳过。

这篇文章的内容是从 java 文档中汇集而来的。

1。无限通配符

The unbounded wildcard type is specified using the wildcard character (?), for example, List<?>. This is called a list of unknown type. There are two scenarios where an unbounded wildcard is a useful approach:

  • If you are writing a method that can be implemented using functionality provided in the Object class.

  • When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear. In fact, Class<?> is so often used because most of the methods in Class<T> do not depend on T.

2。有界通配符

Consider a simple drawing application that can draw shapes such as rectangles and circles. To represent these shapes within the program, you could define a class hierarchy such as this:

public abstract class Shape {
    public abstract void draw(Canvas c);
}

public class Circle extends Shape {
    private int x, y, radius;
    public void draw(Canvas c) {
        ...
    }
}

public class Rectangle extends Shape {
    private int x, y, width, height;
    public void draw(Canvas c) {
        ...
    }
}

These classes can be drawn on a canvas:

public class Canvas {
    public void draw(Shape s) {
        s.draw(this);
   }
}

Any drawing will typically contain a number of shapes. Assuming that they are represented as a list, it would be convenient to have a method in Canvas that draws them all:

public void drawAll(List<Shape> shapes) {
    for (Shape s: shapes) {
        s.draw(this);
   }
}

Now, the type rules say that drawAll() can only be called on lists of exactly Shape: it cannot, for instance, be called on a List<Circle>. That is unfortunate, since all the method does is read shapes from the list, so it could just as well be called on a List<Circle>. What we really want is for the method to accept a list of any kind of shape:

public void drawAll(List<? extends Shape> shapes) {
    ...
}

There is a small but very important difference here: we have replaced the type List<Shape> with List<? extends Shape>. Now drawAll() will accept lists of any subclass of Shape, so we can now call it on a List<Circle> if we want.

List<? extends Shape> is an example of a bounded wildcard. The ? stands for an unknown type, however, in this case, we know that this unknown type is in fact a subtype of Shape. (Note: It could be Shape itself, or some subclass; it need not literally extend Shape.) We say that Shape is the upper bound of the wildcard.

类似地,语法? super T ,它是一个有界通配符,表示一个未知类型,它是 T 的父类(super class)型。 例如,ArrayedHeap280 包​​括 ArrayedHeap280<Integer> , ArrayedHeap280<Number> , 和 ArrayedHeap280<Object> . 正如您在 java documentation for Integer class 中看到的那样, Integer 是 Number 的子类,Number 又是 Object 的子类。

Class Integer * java.lang.Object * java.lang.Number * java.lang.Integer

3。键入删除和 ClassCastException

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:

  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
  • Insert type casts if necessary to preserve type safety.
  • Generate bridge methods to preserve polymorphism in extended generic types.

During the type erasure process, the Java compiler erases all type parameters and replaces each with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded.

Consider the following generic class that represents a node in a singly linked list:

public class Node<T> {

    private T data;
    private Node<T> next;

    public Node(T data, Node<T> next) }
        this.data = data;
        this.next = next;
    }

    public T getData() { return data; }
    // ...
}
```
>Because the type parameter T is unbounded, the Java compiler replaces it with Object:
```java
public class Node {

    private Object data;
    private Node next;

    public Node(Object data, Node next) {
        this.data = data;
        this.next = next;
    }

    public Object getData() { return data; }
    // ...
}

In the following example, the generic Node class uses a bounded type parameter:

public class Node<T extends Comparable<T>> {

    private T data;
    private Node<T> next;

    public Node(T data, Node<T> next) {
        this.data = data;
        this.next = next;
    }

    public T getData() { return data; }
    // ...
}

The Java compiler replaces the bounded type parameter T with the first bound class, Comparable:

public class Node {

    private Comparable data;
    private Node next;

    public Node(Comparable data, Node next) {
        this.data = data;
        this.next = next;
    }

    public Comparable getData() { return data; }
    // ...
}
```
> Sometimes type erasure causes a situation that you may not have anticipated. The following example shows how this can occur. 
> 
> Given the following two classes:
```java
public class Node<T> {

    public T data;

    public Node(T data) { this.data = data; }

    public void setData(T data) {
        System.out.println("Node.setData");
        this.data = data;
    }
}

public class MyNode extends Node<Integer> {
    public MyNode(Integer data) { super(data); }

    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

After type erasure, the Node and MyNode classes become:

public class Node {

    public Object data;

    public Node(Object data) { this.data = data; }

    public void setData(Object data) {
        System.out.println("Node.setData");
        this.data = data;
    }
}

public class MyNode extends Node {

    public MyNode(Integer data) { super(data); }

    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

Consider the following code:

MyNode mn = new MyNode(5);
Node n = mn;            // A raw type - compiler throws an unchecked warning
n.setData("Hello");     
Integer x = mn.data;    // Causes a ClassCastException to be thrown.

After type erasure, this code becomes:

MyNode mn = new MyNode(5);
Node n = (MyNode)mn;         // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = (String)mn.data; // Causes a ClassCastException to be thrown.

Here is what happens as the code is executed:

  • n.setData("Hello"); causes the method setData(Object) to be executed on the object of class MyNode. (The MyNode class inherited setData(Object) from Node.)
  • In the body of setData(Object),

the

data n 引用的对象的字段分配给 String .

  • The data field of that same object, referenced via mn, can be accessed and is expected to be an Integer (since mn is a MyNode which is a Node<Integer>.Trying to assign a String to an Integer causes a ClassCastException from a cast inserted at the assignment by a Java compiler.

关于java.lang.ClassCastException : [Ljava. lang.Comparable;不能转换到,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18292282/

相关文章:

java - 在 JDialog 之后需要点击 JButton 两次

java - 如何消除 JVM 运行时错误弹出窗口?

java - jar 中存在的类出现 NoClassDefFoundError

java - 如何解决此错误 VFY : unable to resolve virtual method

java - 修改 JSON 结构中的所有字符串基元

java - 如何计算 GWT 2.3 中的指数?

java - GWT 项目中的 Spring 配置?

java - 为什么 Math 类中的 nextUp 方法会跳过一些值?

java - 移动java应用程序

java - Hibernate 4 注释配置