我有(另一个)未经检查的演员问题。我 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>
因为传入参数的 bird
保证是 Bird
。
测试支持了我的理论,但我想确保我的想法是正确的。 此代码是否有任何不安全的地方?
更新
感谢您的回答。由于这些答案,我意识到我的结构中存在弱点并对其进行了修改。
本质上,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());
}
}
我再次收到同样的警告,但这似乎更安全。
这样更好吗,安全吗?
I have (another) unchecked cast question. I am 90% sure that it is safe, but I want to make sure (I'm justifying the use of @SupressWarnings
to another developer who is reviewing the code)
The following pattern has been set up by our framework:
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);
}
}
I am also using a subclass of Writer
to write a class that makes use of generics:
class Color {}
class Green extends Color {}
class Brown extends Color {}
My writer class looks like this:
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());
}
}
I could use raw types in the writer but that gives many more warnings. Instead I include the generics in the Writer class. This is fine everywhere but the constructor. I am forced to cast the bird.getClass()
(which is a class object which has no generic signature) to a Class object with a generic signature. This produces an unchecked cast warning on the cast, but I believe it is safe to cast the result to Class<Bird<C>>
because the bird
that is passed into the parameter is guaranteed to be a Bird<C>
.
Testing backs up my theory, but I want to make sure that my thinking is correct. Is there any way in which this code is unsafe?
Update
Thanks for your answers. Because of the answers I realized there was a weakness in my structure and have revised it.
Essentially Cat
uses a simple Writer
that knows it's always writing a Cat
. In my case, I've got a type of "SmartAnimal" that can be written by a dynamic Writer, so that I don't have to create a Writer
for every 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());
}
}
Again, I have the same warning, but this seems to be more safe.
Is this better, and is it safe?
发布评论
评论(3)
你并不完全正确。正确、安全但仍未经检查的转换是
Class>
,因为您传递的鸟可能是一只 Owl,它会返回一个Class
,它可以分配给一个类>
。彼得·劳瑞(Peter Lawrey)是正确的,因为这是不受控制但安全的。更新:
不,出于同样的原因它仍然不安全。您仍然可以执行类似
new DynamicWriter(new SuperHorse());
的操作,它将执行从Class
到Class 的未经检查的转换;
。为了安全起见,您需要转换为Class
。You are not entirely correct. The correct, safe, but still unchecked cast is to
Class<? extends Bird<C>>
, as the bird you are passed could, for instance, be an Owl, which would return aClass<Owl>
which could be assigned to aClass<? extends Bird<C>>
. Peter Lawrey is correct in the reason that this is unchecked but safe.Update:
No, it is still not safe for the same reason. You can still do something like
new DynamicWriter<Horse>(new SuperHorse());
which would perform an unchecked cast fromClass<SuperHorse>
toClass<Horse>
. To be safe, you need to cast to aClass<? extends A>
.由于 ILMTitan 中列出的原因,这肯定是不正确的他的回答。但我会给你一个原因,为什么它也可能不太安全。想象一下,您有一个方法
verifyType()
来确保传入写入的任何内容都是正确的类型:您希望该方法永远不会失败,对吧?毕竟,您只需确保
t
是T
(因为您有一个Class
),而且我们已经知道了是一个T
,因为write()
只接受一个T
?正确的? 错误!您实际上并没有检查t
是否是T
,而是可能检查T
的某种任意子类型。检查一下如果您声明一个
Writer>
并用Parrot
实例化它,会发生什么,它将是合法的 执行此调用:您不会期望它会失败。但是,您的值类型仅适用于
Parrot
,因此类型检查将会失败。这完全取决于你在作家课上做什么,但要预先警告:你正在踏入危险的水域。声明一个类 会防止您犯这样的错误。
It is most certainly not correct, for the reason listed by ILMTitan in his answer. But I'll give you a reason why it might also not be very safe. Imagine you had a method
verifyType()
that made sure that anything that was passed in for writing was the correct type:This method you would expect never to fail, right? After all, you're just ensuring that
t
is aT
(since you have aClass<T>
), and we already know it is aT
becausewrite()
only accepts aT
? Right? Wrong! You're not actually checking ift
is aT
, but potentially some arbitrary subtype ofT
.Examine what would happen if you declared a
Writer<Bird<Green>>
and instantiated it with aParrot<Green>
, it would be legal to do this call:And again you would not expect it to fail. However your value type is for
Parrot
only, so the type check would fail. It all depends what you're doing in your writer class, but be forewarned: you are treading in dangerous water here. Declaring aClass<? extends T>
in your writer would prevent you from making a mistake like this.恕我直言,它是安全的。问题是 getClass() 在运行时返回对象的类,但编译器不理解 getClass() 的作用,也没有一种语法可以执行类似的操作,
因为它是唯一的示例何时使用它。
IMHO, its safe., The problem is that getClass() returns the class of the object at runtime, but the compiler doesn't understand what getClass() does, nor is there a syntax which does something like
possibly because its the only example of when it would be used.