java.lang.ClassCastException: [Ljava.lang.Comparable;无法投射到

2024-04-06

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

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

其中 Element 定义如下:

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.无限通配符

无界通配符类型使用通配符 (?), 例如,List<?>。这称为未知类型列表。在两种情况下,无界通配符是一种有用的方法:

  • 如果您正在编写一个可以使用 Object 类中提供的功能来实现的方法。

  • 当代码使用泛型类中不依赖于类型参数的方法时。例如,List.size or List.clear。实际上,Class<?>之所以如此频繁地使用,是因为大多数方法Class<T>不依赖T.

2. 有界通配符

考虑一个可以绘制矩形和圆形等形状的简单绘图应用程序。为了在程序中表示这些形状,您可以定义一个类层次结构,如下所示:

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) {
        ...
    }
}

这些类可以在画布上绘制:

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

任何绘图通常都会包含许多形状。假设它们被表示为一个列表,那么在 Canvas 中有一个方法来绘制它们将会很方便:

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

现在,类型规则说drawAll()只能在完全形状的列表上调用:例如,它不能在List<Circle>。这是不幸的,因为该方法所做的只是从列表中读取形状,所以它也可以在List<Circle>。我们真正想要的是该方法接受任何形状的列表:

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

这里有一个很小但非常重要的区别:我们替换了类型List<Shape> with List<? extends Shape>. Now drawAll()将接受任何子类的列表Shape,所以我们现在可以调用它List<Circle>如果我们愿意的话。

List<? extends Shape>是有界通配符的示例。这?代表未知类型,但是,在这种情况下,我们知道这个未知类型实际上是 Shape 的子类型。 (注意:它可以是 Shape 本身,也可以是某个子类;它不需要从字面上扩展 Shape。)我们说 Shape 是上限通配符的。

类似地,语法? super T是有界通配符,表示未知类型,是 T 的超类型。 例如,ArrayedHeap280 包​​括ArrayedHeap280<Integer>, ArrayedHeap280<Number>, and ArrayedHeap280<Object>。 正如你在Integer 类的 java 文档 https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html,Integer 是 Number 的子类,而 Number 又是 Object 的子类。

整数类* java.lang.Object * java.lang.Number * java.lang.Integer

3. 键入擦除和ClassCastException

Java 语言中引入泛型是为了在编译时提供更严格的类型检查并支持泛型编程。为了实现泛型,Java 编译器将类型擦除应用于:

  • 如果类型参数无界,则将泛型类型中的所有类型参数替换为其边界或对象。因此,生成的字节码仅包含普通的类、接口和方法。
  • 如有必要,请插入类型转换以保持类型安全。
  • 生成桥接方法以保留扩展泛型类型中的多态性。

在类型擦除过程中,Java 编译器会擦除所有类型参数,如果类型参数是有界的,则将其替换为其第一个边界;如果类型参数是无界的,则将其替换为 Object。

考虑以下表示单链表中的节点的泛型类:

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; }
    // ...
}

在以下示例中,泛型 Node 类使用有界类型参数:

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; }
    // ...
}

Java 编译器将有界类型参数 T 替换为第一个绑定类 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);
    }
}

类型擦除后,Node and MyNode类变为:

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

考虑以下代码:

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.

类型擦除后,此代码变为:

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.

执行代码时会发生以下情况:

  • n.setData("Hello");导致方法setData(Object)在类的对象上执行MyNode. (The MyNode类继承setData(Object) from Node.)
  • 在体内setData(Object),

the

data所引用对象的字段n被分配给一个String.

  • The data同一对象的字段,通过引用mn,可以访问并且预计是Integer (since mn is a MyNode这是一个Node<Integer>.尝试分配一个String to an Integer导致ClassCastException来自 Java 编译器在赋值时插入的强制转换。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java.lang.ClassCastException: [Ljava.lang.Comparable;无法投射到 的相关文章

随机推荐

  • 安装 symfony-cmf-standard 时“执行缓存时发生错误:clear --no-warmup”

    我试图使用以下命令安装 symfony cmf standard composer phar create project symfony cmf standard edition symfony cmf standard stabilit
  • Int[].Contains 在 EF6 中不起作用

    我有一个奇怪的问题 基本上我有这个代码 var langauges from l in context languages where Model LanguageIDs Contains l LanguageID select l ToL
  • 显示 searchResults TableView 时隐藏 UITableView

    我有一个UITableView with a searchDisplayController实施的 我有 tableView backgroundColor UIColor clearColor and self searchDisplay
  • WordPress 网站迁移 - 图标丢失

    我最近按照以下步骤将本地站点迁移到临时服务器https codex wordpress org Moving WordPress https codex wordpress org Moving WordPress一切似乎都工作正常 最初
  • 延迟任务开始的正确方法

    我想安排一个任务在 x 毫秒内启动 并能够在它开始之前 或在任务开始时 取消它 第一次尝试是这样的 var cancelationTokenSource new CancellationTokenSource var token cance
  • 在日志中包含 Active Record 查询的作用

    Rails 现在支持多个数据库角色 默认情况下 https guides rubyonrails org active record multiple databases html using manual connection switc
  • powershell:如何从 [ref] 变量写入主机值

    我是 Powershell 新手 我正在尝试弄清楚如何从函数内打印 ref 变量的值 这是我的测试代码 function testref ref obj1 obj1 value obj1 value 5 write host the new
  • MongoDB 限制查找结果

    如何查询集合并限制返回的结果 假设我有一个包含 500M 文档的数据库 但我只想搜索并返回前 10 个匹配项 而不必搜索整个集合 出于性能原因 理想情况下 我可以在 O m n 时间内返回第 n 到 m 个结果 如果这可能或如何做到 有什么
  • ASP.Net Core 错误 JSON

    我正在玩一点 ASP NET Core 我正在创建一个基本的 webapi 我想在出现问题时显示 JSON 错误 打印屏幕在屏幕上显示我想要的内容 唯一的问题是发送时状态码为 200 catch NullReferenceException
  • 在 Visual Studio 调试器中查看命名空间全局变量?

    在 Visual Studio 2008 中调试非托管 C 项目时 我偶尔想查看全局变量的值 我们没有很多这些 但那些都在名为 全局 的名称空间中声明 例如 namespace global int foo bool bar 问题是 当代码
  • Dockerfile 中的 setfacl 没有效果

    我想在使用 setfacl 构建 docker 映像时为某些文件夹设置默认 acl 但它没有效果 默认 acl 不变 我的目标是在 opt 中创建的每个文件都必须对任何用户都具有 rwX 权限 因为该映像稍后将使用任意 uid 运行 并且需
  • 如何查看 conda 环境的创建日期?

    我创建了四个不同的版本conda virtual environments envs 用于图像处理任务 每个环境包括GDAL and OpenCV 以及相关库和依赖项的一些子集 我想将图像处理环境列表剔除到最近创建的一个 它将拥有我使用的最
  • 在整个项目上运行 CPPlint

    我想跑cplint py https github com google styleguide tree gh pages cpplint在我的整个项目中 不是通过单个文件来获取项目中所有 C C 文件的报告 如何在 macOS 和 Win
  • Java中列出目录和子目录中的所有文件

    列出 1000 多个目录和子目录中的文件名的最快方法是什么 编辑 我当前使用的代码是 import java io File public class DirectoryReader static int spc count 1 stati
  • 如何使用 SwiftUI 在 ScrollView 中选择一个项目?

    我想要完成的是有一个项目循环 我可以点击其中一个项目 一旦点击它就会以编程方式变得更大 这是我的代码和到目前为止的结果 struct ContentView View State var emojisArray State var sele
  • 如何存储在多重图中使用的 ggplots 列表而不覆盖以前的图?

    我想使用从另一个函数创建的对象 cd参数如下 协方差矩阵存储在 3 维数组中 因此cd covmat i 称为第 i 个协方差矩阵 最初我对复制相同的情节有一些疑问 但是 我发现我遇到了环境问题 我尝试了多种方法来解决这个问题 下面的代码是
  • 我如何对 pandas 中的语义版本进行排序?

    我有一个软件版本列表 软件遵循语义版本规范 即有主版本 次版本和补丁版本 0 1 0 2 0 2 1 0 3 0 10 0 10 1 pandas 有没有办法对这些版本进行排序 使 0 2 大于 0 1 但小于 0 10 熊猫解决方案sor
  • asp.net core 3 rotativastartup.cs环境问题

    我尝试使用 Rotativa 我按照这个guide https www youtube com watch v 68YcKP0g1XA在 start cs 的配置函数中添加此代码 RotativaConfiguration Setup en
  • XCodeBuild -exportArchive 不允许我指定文件名

    我正忙于 Jenkins 构建 该构建将用于构建 iOS 应用程序 我已成功使用以下命令创建存档 xcodebuild archive archivePath build app xcarchive 现在我正在尝试导出该存档指定输出文件名
  • java.lang.ClassCastException: [Ljava.lang.Comparable;无法投射到

    我的代码中出现以下异常 线程 main 中的异常 java lang ClassCastException Ljava lang Comparable 无法转换为 LElement 在以下调用中 Element