Java泛型-将可分配的捕获类型强制转换为子类
我在Java泛型中有以下场景:Java泛型-将可分配的捕获类型强制转换为子类,java,generics,Java,Generics,我在Java泛型中有以下场景: public abstract class A<T> { protected final Class<T> typeOfX; public A(final Class<T> typeOfX) { this.typeOfX = typeOfX; } public abstract void load(final T x); } public class AnyA<S>
public abstract class A<T> {
protected final Class<T> typeOfX;
public A(final Class<T> typeOfX) {
this.typeOfX = typeOfX;
}
public abstract void load(final T x);
}
public class AnyA<S> extends A<S> {
private final Map<String, A<? extends S>> map;
public AnyA(final Class<S> superTypeOfX,
final Map<String, A<? extends S>> map) {
super(superTypeOfX);
this.map = map;
}
@Override
public void load(final S superx) {
for (final A<? extends S> a: map.values())
if (a.typeOfX.isAssignableFrom(superx.getClass())) //Here I want to say: "if superx can be casted to a.typeOfX".
a.load(a.typeOfX.cast(superx)); //Here I want to cast superx to a.typeOfX (so as to call the load method). Here's the compile error.
}
}
公共抽象类A{
受保护的最终类typeOfX;
公共A(最终类别X){
this.typeOfX=typeOfX;
}
公共抽象空荷载(最终T x);
}
公共类AnyA扩展了{
私人最终地图请注意,无论您做什么,代码在任何情况下都不是“语法类型安全的”。有未经检查的类型,唯一防止出现错误的安全带是isAssignableFrom
检查
(这通常是可以的,我只是为了完整性才提到它)
当您将这些行分开时,错误的原因可能更为明显(根据-请遵循它们!)这里,S
代表SuperType
)
我认为引起困惑的主要原因是:打电话的时候
Object s = a.typeOfX.cast(s);
而typeOfX
是String.class
,则强制转换的返回类型将不是String
,而是编译器此时可以推断的类型。在上面的示例中,这是对象
但是,您已经提到了,实际上,通过一些技巧,您可以编译
但是…(见下面的注释)
我不熟悉java语法,但“SuperType”不应该是已定义的类类型吗?@Phate01这至少不是编译器错误。“SuperType”据我所知是任何扩展对象的类,即任何类。虽然它可能与问题有关,但我不知道。@Phate01它不是强制性的,但对giv来说是一个强大的约定e类型参数名称不能被误认为类名-通常是大写的单字母名称。因此,应将SuperType
改为S
。如果其他人读到这一点,我将“S”类型命名为“SuperType”,然后我将其从“SuperType”改为“S”,按照我被提示的命名约定。好的。我理解;代码现在对于更改来说不是很“安全”,也不是很可读,也不是最佳实践,但比更改类图要好,这取决于整个项目。我想这是一个艰难的决定。注意;我做了“”((a)a)。加载(superx)“我没有被提示取消任何警告。当然谢谢你。@thanopi57使用((A)A…
),你使用的是“原始类型”。这基本上关闭了此上下文中的任何类型检查,但通常也会生成警告(这取决于-它可能在IDE中被禁用)。
A<String> specificA = ...;
// So the "specificA" can load "String" objects. Then this is fine:
A<? extends Object> a = specificA;
Object s = a.typeOfX.cast(s);
// But here's the error: "s" is only an Object, and not a String!
a.load(s);
Object s = a.typeOfX.cast(s);
import java.util.Map;
abstract class A<T>
{
protected final Class<T> typeOfX;
public A(Class<T> typeOfX)
{
this.typeOfX = typeOfX;
}
public abstract void load(T x);
}
class AnyA<S> extends A<S>
{
private final Map<String, A<? extends S>> map;
public AnyA(Class<S> superTypeOfX,
Map<String, A<? extends S>> map)
{
super(superTypeOfX);
this.map = map;
}
@Override
public void load(S s)
{
for (A<? extends S> a : map.values())
{
if (a.typeOfX.isAssignableFrom(s.getClass()))
{
callLoad(a, s);
}
}
}
private static <S, T extends S> T cast(A<T> a, S s)
{
T t = a.typeOfX.cast(s);
return t;
}
private static <T, S extends T> void callLoad(A<S> a, T s)
{
a.load(cast(a, s));
}
}
for (A<? extends S> a : map.values())
{
if (a.typeOfX.isAssignableFrom(superx.getClass()))
{
// This call is safe as of the check done above:
@SuppressWarnings("unchecked")
A<Object> castA = (A<Object>) a;
castA.load(superx);
}
}