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

时间:2011-01-26 22:16:55

标签: java generics casting warnings

我有(另一个)未经检查的演员问题。我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());
    }
}

同样,我也有同样的警告,但这似乎更安全。

这样更好,是否安全?

3 个答案:

答案 0 :(得分:4)

你并不完全正确。正确,安全但仍未经检查的演员阵容是Class<? extends Bird<C>>,因为您传递的鸟可能是猫头鹰,它会返回Class<Owl>,可以分配给{{1} }}。彼得劳里是正确的,因为这是不受制约但安全的。

更新

不,出于同样的原因,它仍然不安全。您仍然可以执行Class<? extends Bird<C>>之类的操作,这会执行从new DynamicWriter<Horse>(new SuperHorse());Class<SuperHorse>的未经检查的广播。为安全起见,您需要转换为Class<Horse>

答案 1 :(得分:3)

由于ILMTitan in his answer列出的原因,这肯定是不正确的。但我会告诉你为什么它也可能不太安全。想象一下,你有一个方法verifyType(),确保传入的任何内容都是正确的类型:

public void write(T t) {
   if (!verifyType(t)) explode();
   //...do write
}

public boolean verifyType(T t) {
   return valueType.isInstance(t);
}

你期望这种方法永远不会失败,对吗?毕竟,您只是确保tT(因为您有Class<T>),我们已经知道 a {{1因为T只接受write()?对? 错误!您实际上并未检查T是否为t,但可能是某个T的任意子类型。

检查如果您声明T并使用Writer<Bird<Green>>对其进行实例化会发生什么情况,执行此调用将是 legal

Parrot<Green>

再次你不会指望它会失败。但是,您的值类型仅适用于Writer<Bird<Green>> writer; writer.write(new SomeOtherGreenBird()); ,因此类型检查将失败。这一切都取决于你在作家班上所做的事情,但要预先警告:你在这里踩着危险的水。在你的作家中声明Parrot可以防止你犯这样的错误。

答案 2 :(得分:1)

恕我直言,它是安全的。问题是getClass()在运行时返回对象的类,但是编译器不理解getClass()的作用,也没有像

Class<this> getClass();

可能是因为它是使用它的唯一例子。