如何动态转换/确保具有不同泛型的集合的类型安全
我决定在我的设计中使用泛型,效果很好。只有当我达到抽象时,我才陷入困境。我正在收集使用不同泛型实现相同接口的不同实例。据我所知,为了将它们保存在列表中,我需要使用通配符。所以我当前的代码是这样的:
import java.util.List;
import java.util.ArrayList;
public class Main {
private List<IView<?>> views = new ArrayList<IView<?>>();
public void addView(IView<?> view)
{
this.views.add(view);
}
public void handle()
{
for (IView<?> view : this.views)
{
// ## ERROR ##
view.render(
view.cast(new Object())
);
}
}
}
public interface IView<T> {
public T cast(Object entity);
public void render(T entity);
}
public class FirstView implements IView<One> {
// .. Added to Main-collection views
}
public class SecondView implements IView<Two> {
// .. Added to Main-collection views
}
我还尝试了另一种方法,从 IView 返回一个类,然后用它来调用 class.cast。同样的问题。
编译器不接受这一点 - IView(Capture#2-of ?) 类型中的 Render(Capture#2-of ?) 方法不适用于参数 (Capture#3-of ?)。
我部分地想理解这个问题,但我看不出有什么办法解决它。如果有人能帮助我重新开始,我将非常感激。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不相信您可以为
?
“类型化”变量赋值。一个无限的“?”意味着“变量的原始类型未知”,这意味着没有已知类型可以安全地分配给它。这并不意味着在运行时检索类型参数的实际值。使用泛型方法进行强制转换的整个想法在 Java 泛型中没有意义。以类型安全的方式对未知类型对象进行强制转换的唯一方法是使用实际强制转换。
唯一的解决方案是摆脱cast()方法,并使用原始类型:
假设cast()方法只进行强制转换,而不进行类型转换。如果最终调用的实现方法是 FirstView.render(One object),我相信 Java 实际上会将参数强制转换为 One。 (这也可能导致有趣的错误,即在没有强制转换的代码行上抛出 ClassCastException。)
如果
cast()
可以进行类型转换(在这种情况下,“cast”是一个坏名字对于操作),这意味着每个 IView必须能够接受对象,在这种情况下,将render()
的参数设置为没有多大意义首先是泛型类型。我将使用的设计如下:封装“cast”操作。
没有静态类型安全的方法来处理不同类型的对象集合 - 在 Java 中,
IView
和IView
的类型与一样不同>String
和Integer
并且两者之间不存在安全转换。I don't believe you can assign a value to an
?
"typed" variable. An unbounded "?" means "the original type of the variable is unknown", which means there is no known type it's safe to assign to it. It doesn't mean that the actual value of the type parameter is retrieved at runtime.The entire idea of using a generic method to do a cast doesn't make sense in Java generics. The only way to do a cast of an unknown type object in a type-safe way is with an actual cast.
The only solution is to get rid of the cast() method, and use raw types:
Assuming the cast() method is only doing casting and not type conversion. If the implementing method that ends up being called is FirstView.render(One object), I believe Java will actually cast the parameter to One. (This can also cause amusing bugs where a ClassCastException is thrown on a line of code with no casts.)
If
cast()
can do a type conversion (in which case, "cast" is a bad name for the operation), that means that every IView must be able to accept Object, in which case it doesn't make much sense have the parameter ofrender()
be the generic type to begin with. The design I would use is something like the following:encapsulating the "cast" operation.
There is no statically typesafe way to work with a collection of objects of different types - in Java,
IView<One>
andIView<Two>
are types as different asString
andInteger
and there are no safe conversions between the two.由于我想知道代码
view.render(view.cast(new Object());
中的两个捕获,我阅读了Angelika Langer 的泛型常见问题解答中的相应部分。它指出:
时期。
因此,使用通配符声明可以防止使用参数化参数,即使类型推断很简单,就像您的情况一样:( 因此
view.cast(new Object();
是允许的,但view .render(view.cast(new Object());
不是。为了通过示例进行说明,Angelika 给出了以下内容:
其中
contains
将 Box 的参数化类型作为参数她说:因此,她建议返回到
Object
(类似于我其他答案中的建议)。顺便说一句,她不鼓励使用原始类型,正如 Josh Bloch 在 Effective Java's 项目中所做的那样23、“不要在新代码中使用原始类型”。Since I was wondering about the two captures in code
view.render(view.cast(new Object());
,I read the appropriate section in Angelika Langer's Generics FAQ. It states that:
PERIOD.
So using a wildcard declaration prevents the use of parameterized arguments, even if type inference were simple, as in your case :( Hence
view.cast(new Object();
is allowed, butview.render(view.cast(new Object());
isn't.Just for clarification via an example, Angelika gives the following:
where
contains
takes as argument the parameterized type of Box. She states:So she suggests retrieting back to
Object
(similarly to the suggestion in my other answer). Btw, she discourages using raw types, as does Josh Bloch in Effective Java's item 23, "Don’t use raw types in new code".我不明白编译器错误,即为什么
view.render(view.cast(new Object());
生成两个捕获。(我已经用view
是最终的,并且显示相同的错误消息)。但是由于
IView
和IView
仅将Object
作为通用类型。 ,解决的方法是使用列表>
。I do not understand the compiler error, i.e. why
view.render(view.cast(new Object());
produces two captures. (I've tried this code withview
being final, and the same error message shows).But since
IView<One>
andIView<Two>
only haveObject
as common type, the way of solving it is usingList<IView<Object>>
.我通过返回一个类型化的对象来替换了转换(并且我通过用 IEntity 替换新的 Object 稍微改变了示例);
通配符在某种程度上是有界的,但它会产生另一个问题(实际上可能是相同的):有没有办法检查两个通配符是否匹配,即:
Where?只能是一种(=相同)(通用)类型?
I sort of replaced the casting by returning a typed object (and I slightly changed the example by replacing the new Object with IEntity);
The wildcard is someway bounded, but then it creates another problem (which may actually be the same): Is there a way to check that two wildcards match, i.e.:
Where ? can only be one (=the same) (generic)type?