[英]Java Generics - is this unchecked cast safe?
我有(另一个)未经检查的演员问题。 我90%确定它是安全的,但我想确定(我正在证明将@SupressWarnings
用于正在审查代码的其他开发人员)
我们的框架已经建立了以下模式:
abstract class Writer<T> {
Class<T> valueType;
Writer(Class<T> valueType) {
this.valueType = valueType;
}
}
class Cat { }
class CatWriter extends Writer<Cat> {
CatWriter() {
super(Cat.class);
}
}
我也使用Writer
的子类来编写一个使用泛型的类:
class Color {}
class Green extends Color {}
class Brown extends Color {}
我的作家类看起来像这样:
abstract class Bird<C extends Color> {}
class Parrot extends Bird<Green>{}
class Ostrich extends Bird<Brown>{}
class BirdWriter<C extends Color> extends Writer<Bird<C>> {
BirdWriter(Bird<C> bird) {
super((Class<Bird<C>>)bird.getClass());
}
}
我可以在编写器中使用原始类型但是会提供更多警告。 相反,我在Writer类中包含泛型。 除了构造函数之外,这到处都很好。 我不得不投的bird.getClass()
这是一类对象,它没有一般签名) 与通用签署的Class对象。 这会在演员表上产生未经检查的演员警告,但我相信将结果转换为Class<Bird<C>>
是安全的,因为传递给参数的bird
肯定是Bird<C>
。
测试支持我的理论,但我想确保我的想法是正确的。 这段代码有什么方法不安全吗?
谢谢你的回答。 由于答案,我意识到我的结构存在缺陷,并对其进行了修改。
基本上Cat
使用一个简单的Writer
,它知道它总是写一个Cat
。 在我的例子中,我有一种可以由动态Writer编写的“SmartAnimal”,因此我不必为每个Animal创建一个Writer
。
class SmartAnimal {}
class Dog extends SmartAnimal {}
class Horse extends SmartAnimal {}
class SuperHorse extends Horse {}
class DynamicWriter<A extends SmartAnimal> extends Writer<A> {
DynamicWriter(A smartAnimal) {
super((Class<A>)smartAnimal.getClass());
}
}
同样,我有同样的警告,但这似乎更安全。
这样更好,安全吗?
你并不完全正确。 正确的,安全的,但仍未经检查的演员表是Class<? extends Bird<C>>
Class<? extends Bird<C>>
,因为您传递的鸟可以是一只猫头鹰,它会返回一个Class<Owl>
,可以分配给一个Class<? extends Bird<C>>
Class<? extends Bird<C>>
。 彼得劳里是正确的,因为这是不受制约但安全的。
更新:
不,出于同样的原因,它仍然不安全。 你仍然可以做一些像new DynamicWriter<Horse>(new SuperHorse());
这将执行从Class<SuperHorse>
到Class<Horse>
的未经检查的演员表。 为了安全起见,你需要施放到一个Class<? extends A>
Class<? extends A>
。
由于ILMTitan 在他的回答中列出的原因,这肯定是不正确的。 但我会告诉你为什么它也可能不太安全。 想象一下,你有一个方法verifyType()
,它确保传入的任何内容都是正确的类型:
public void write(T t) {
if (!verifyType(t)) explode();
//...do write
}
public boolean verifyType(T t) {
return valueType.isInstance(t);
}
你期望这种方法永远不会失败,对吧? 毕竟,你只是确保t
是T
(因为你有一个Class<T>
),我们已经知道它是 T
因为write()
只接受一个T
? 对? 错误! 您实际上并不检查是否t
是T
,但潜在的一些任意亚型T
。
检查如果你声明一个Writer<Bird<Green>>
并用Parrot<Green>
实例化它会发生什么,这样做是合法的 :
Writer<Bird<Green>> writer;
writer.write(new SomeOtherGreenBird());
再一次,你不会指望它会失败。 但是,您的值类型仅适用于Parrot
,因此类型检查将失败。 这一切都取决于你在作家班上所做的事情,但要预先警告:你在这里踩着危险的水。 宣布一个Class<? extends T>
在你的作家中Class<? extends T>
会阻止你犯这样的错误。
恕我直言,这是安全的。问题是getClass()在运行时返回对象的类,但是编译器不理解getClass()的作用,也没有类似的语法
Class<this> getClass();
可能是因为它是它何时被使用的唯一例子。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.