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

Nic*_*ole 5 java generics warnings casting

我有(另一个)未经检查的演员问题.我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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我也在使用子类Writer来编写一个使用泛型的类:

class Color {}
class Green extends Color {}
class Brown extends Color {}
Run Code Online (Sandbox Code Playgroud)

我的作家类看起来像这样:

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以在编写器中使用原始类型但是会提供更多警告.相反,我在Writer类中包含泛型.除了构造函数之外,这到处都很好.我不得不投的bird.getClass()(这是一个类对象,它没有一般签名)到Class对象一个通用的签名.这会在转换中产生未经检查的强制转换警告,但我相信将结果转换为是安全的,Class<Bird<C>>因为bird传递给参数的那个被保证为a Bird<C>.

测试支持我的理论,但我想确保我的想法是正确的. 这段代码有什么方法不安全吗?


更新

谢谢你的回答.由于答案,我意识到我的结构存在缺陷,并对其进行了修改.

基本上Cat使用一个Writer知道它总是写一个的简单Cat.在我的例子中,我有一种可以由动态Writer编写的"SmartAnimal",因此我不需要Writer为每个Animal 创建一个.

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

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

这样更好,安全吗?

Mar*_*ers 3

由于 ILMTitan在他的回答中列出的原因,这肯定是不正确的。但我会给你一个原因,为什么它也可能不太安全。想象一下,您有一个方法verifyType()可以确保传入的任何写入内容都是正确的类型:

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

public boolean verifyType(T t) {
   return valueType.isInstance(t);
}
Run Code Online (Sandbox Code Playgroud)

您希望这种方法永远不会失败,对吗?毕竟,您只是确保它t是 a T(因为您有 a Class<T>),并且我们已经知道它aT因为write()只接受T? 正确的? 错误的! 您实际上并没有检查是否t是 a T,而是可能检查 的某种任意子类型T

检查如果声明 aWriter<Bird<Green>>并用 a 实例化它会发生什么,执行此调用Parrot<Green>合法的:

Writer<Bird<Green>> writer;
writer.write(new SomeOtherGreenBird());
Run Code Online (Sandbox Code Playgroud)

同样,你不会期望它会失败。但是,您的值类型仅适用于Parrot,因此类型检查将失败。这完全取决于你在作家课上做什么,但要预先警告:你正在踏入危险的水域。在你的 writer 中声明 aClass<? extends T>可以防止你犯这样的错误。