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>

我在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> 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);
    }
}