繁体   English   中英

Java Generics - 这个未经检查的演员安全吗?

[英]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);
}

你期望这种方法永远不会失败,对吧? 毕竟,你只是确保tT (因为你有一个Class<T> ),我们已经知道它 T因为write()只接受一个T 对? 错误! 您实际上并不检查是否tT ,但潜在的一些任意亚型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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM