对于从Object
到泛型的类型转换,遇到警告Type safety: Unchecked cast from Object to Edge
Edge<?> other = (Edge<?>) otherObject; |
具体分析见下文。
重写equals
新写的类最好要重写(Override) equals()
以及hashCode()
,以便其它方法的调用,比如说Collection
的contains()
、HashSet
的查找等。
String
类
先来看看String
类对这两个方法的重写。
String
的equals
:
/** |
String
的hashCode
:
/** |
泛型(Generic)重写equals()
的问题
图ConcreteEdgeGraph<L>
的内部实现有一个Edge<L>
类,我在重写equals
遇到了问题。
// if two edges have same source and target, they are equal |
这段代码中,在
// now we know otherObject is a non-null Edge<L> |
处,Eclipse报出静态警告:Type safety: Unchecked cast from Object to Edge
意即类型转换没有进行检查,Java不知道这种转换是否安全。
虽然之前已经用getClass()
确定了otherObject
就是Edge
的实例,但getClass()
函数返回的是擦除后的类,也就是说Edge<String>
和Edge<Object>
返回的是同一个类Edge
。
Stackoverflow[4]上给出了建议的做法,这也是Eclipse提供的Quick fix:
Yes - this is a natural consequence of type erasure. If o is actually an instance of Action
that won’t be caught by the cast - you’ll only see the problem when you try to use it, passing in a ClientInterface instead of a string.
You can get rid of the warning using:
"unchecked") ( |
as a function annotation, but you can’t easily sort out the underlying problem :(
当自己知道这样做是安全的的时候,可以选择镇压(suppress)警告。
那么有没有更好的解决办法呢?Java为何警告,我们究竟如何检查这样的类型转换转换是否安全?
Raw Types[1]
原始(raw)类型是指不带类型参数的泛型类或接口。比如有一个泛型类Box<T>
:
public class Box<T> { |
你可以创建参数化(parameterized)类型Box<T>
:
Box<Integer> intBox = new Box<>(); |
而原始类型则是这样的:
Box rawBox = new Box(); |
在JDK5.0之前,很多类(比如Collections
)不是泛型,因此原始类型在其中很常见。使用Box
会将泛型进行擦除,也就是把Box<T>
实现中的T
全部替换为Object
,从而产生一个新的类。为了向后兼容,Java允许参数化类型赋值给原始类型:
Box<String> stringBox = new Box<>(); |
但是不允许原始类型赋值给参数化类型、一种参数化类型赋值给另一种参数化类型:
Box<Object> objectBox = new Box<>(); |
再将上面代码加入一个类型转换:
objectBox = (Box<Object>)rawBox; |
这就出现了与之前一样的警告:Type safety: Unchecked cast from Box to Box<Object>,这是因为你尝试将原始类型转换为参数化类型时,或是一种参数化类型转换为另一种参数化类型。
查了许多资料,最终了解到这是因为这种转换过程不安全,因为编译器无法肯定rawBox
就是Box<Object>
而不是Box<Integer>
、Box<Double>
等等,改用通配符就可以解决这个问题:
Box<?> otherBox = (Box<?>)rawBox; |
这样的话,在使用getClass()
判断之后确定了rawBox
是类Box
的实例,将其downcast(向下转换,即超类转为子类)为Box<?>
是绝对安全的。
回到自己遇到的的问题上来,equals()
函数只需要将Object
转换为Edge<?>
即可使用其中的source
等来比较是否相等,不需要具体到Edge<L>
,因此可以修改为通配符形式:
Edge<?> other = (Edge<?>) otherObject; |