【问题标题】:JAVA Type casting to a class nested inside a generic classJAVA 类型转换为嵌套在泛型类中的类
【发布时间】:2022-11-27 21:18:27
【问题描述】:
package LinkedList;

public class Linkedlist<T> {
    private int size;
    Node head;
    Node tail;

    public Linkedlist() {// default constructor
        size = 0;
        head = null;
        tail = null;
    }
public class Node {// Node class
        T data;// current node data
        Node next;// reference to next node
        Node prev;// reference to previous node

        public Node(T data) {// def constructor
            this.data = data;
            next = null;
            prev = null;
        }
@Override // to check equality of two nodes
        public boolean equals(Object obj) {
            if (this == obj)// checks if both have same reference
                return true;
            if (obj == null ||this==null || this.getClass() != obj.getClass())
                return false;
            @SuppressWarnings("unchecked")//casting obj to node gives a unchecked cast warning.
            Node n=((Node)obj);
            if(!(this.data==n.data))
                return false;
            return true; 
        }

与上面的代码一样,我有一个嵌套 Node 类的通用类 Linkedlist。 代码的功能非常明显(我正在尝试创建一个双向链表)。问题是,在 Node 类的 equals 函数中,我将对象 obj 类型转换为 Node,它给出了我目前已抑制的未经检查的强制转换警告。 来自 vs 代码的自动生成的 equals 函数给出了同样的警告。我知道这个警告一定意味着我的代码在运行时可能会以某种方式中断,但我不知道如何中断,而且我对一般的泛型和编程有点陌生。有什么办法可以解决此警告?

【问题讨论】:

  • “我知道这个警告一定意味着我的代码在运行时可能会以某种方式中断”不,它并不总是意味着那个。演员是安全的。
  • 那么有没有什么办法可以“安全地”施放它来消除警告,或者我是否已经抑制了警告?我仍在学习 Java,所以这可以解释我对警告的不满。我只想知道在这里抑制警告是否是最佳做法,或者我可以做更多的事情。

标签: java generics typecasting-operator unchecked-cast


【解决方案1】:

我知道这个警告一定意味着我的代码在运行时可能会以某种方式中断

不,它并不总是那个意思。这只是意味着在运行时,JVM 无法检查转换是否有效,因为您正在转换参数化(也称为通用)类型。 Node这里其实是参数化类型,因为它是参数化类型的非静态内部类,LinkedList&lt;T&gt;

由于运行时(type erasure)的限制,它无法区分例如LinkedList&lt;String&gt;.NodeLinkedList&lt;Integer&gt;.Node。运行时认为它们是同一类型,如果您尝试将一个转换为另一个,则允许转换成功。但是,从编译器(希望也是您)的角度来看,这些是不兼容的类型,不应允许强制转换。毕竟一个只能存Integers,一个只能存Strings。这就是它告诉您运行时无法检查转换是否有效的原因。

未经检查的演员表是否“危险”取决于你做什么它。假设您不小心将 LinkedList&lt;U&gt;.Node 转换为 LinkedList&lt;T&gt;.Node 而不知道出了什么问题。转换会成功并且不会抛出异常。只会抛出异常后来下线,当您尝试将节点的 data 获取为 T 时,它实际上是 U。这通常会使调试真正的原因变得困难。但是如果你不在节点的data上做任何T特定的事情,那么就不会出错。

这正是您的equals 实现中发生的事情。转换后,您只是将 datas 与 == 进行比较。这是你可以用任何两个Objects 做的事情。您只是将 data 视为 Object,它确实是,而不是 T

所以未经检查的演员表在这里是安全的。它源于 JVM 的限制。压制它是你能做的最好的事情。

需要注意的是,您的 equals 实现会将 LinkedList&lt;T&gt;.NodeLinkedList&lt;U&gt;.Nodedata = null 视为相等。由于 null 等于 null。根据您的链接列表是否允许 null,这可能重要也可能不重要。如果你想解决这个问题,你可以添加一个Class字段来记录链表存储的类型:

private final Class<T> clazz;

public Linkedlist(Class<T> clazz) {
    this.clazz = clazz;
    ...

然后将其传递给 Node 构造函数中的 Node

private final Class<T> clazz;

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

然后你也可以检查equals实现中的clazz

Node n = ((Node) obj);
return this.clazz == n.clazz && this.data == n.data;

【讨论】:

  • 这肯定回答了我的问题,并向我清楚地解释了很多概念。非常感谢!
  • @Karan8404 如果您认为我的回答回答了您的问题,请考虑通过单击该复选标记来接受它!
【解决方案2】:

您可以使用它来避免强制转换警告

if (!(obj instanceof LinkedList<?>.Node)) return false;
LinkedList<?>.Node node = (LinkedList<?>.Node) obj;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多