泛型和铸造到正确的类型

时间:2012-03-20 10:13:09

标签: java generics

我的问题可以通过这个片段总结出来:

public interface TheClass<T> {
    public void theMethod(T obj);
}

public class A {
    private TheClass<?> instance;

    public A(TheClass<?> instance) {
        this.instance = instance;
    }

    public void doWork(Object target) {
        instance.theMethod(target); // Won't compile!

        // However, I know that the target can be passed to the
        // method safely because its type matches.
    }
}

我的班级A使用TheClass的实例,其泛型类型未知。它具有一个目标传递为Object的方法,因为TheClass实例可以使用任何类进行参数化。但是,编译器不允许我像这样传递目标,这是正常的。

我应该怎样做才能绕过这个问题?

一个肮脏的解决方案是将实例声明为TheClass<? super Object>,它工作正常,但在语义上是错误的......

我之前使用的另一个解决方案是将实例声明为原始类型,只是TheClass,但这是不好的做法,所以我想纠正我的错误。

解决方案

public class A {
    private TheClass<Object> instance; // type enforced here

    public A(TheClass<?> instance) {
        this.instance = (TheClass<Object>) instance; // cast works fine
    }

    public void doWork(Object target) {
        instance.theMethod(target); 
    }
}

3 个答案:

答案 0 :(得分:4)

public class A {
    private TheClass<Object> instance;

    public A(TheClass<Object> instance) {
        this.instance = instance;
    }

    public void do(Object target) {
        instance.theMethod(target); 
    }
}

public class A<T> {
    private TheClass<T> instance;

    public A(TheClass<T> instance) {
        this.instance = instance;
    }

    public void do(T target) {
        instance.theMethod(target);
    }
}

答案 1 :(得分:1)

解决方案也是键入A。使用通配符?会使您丢失TheClass的类型信息,并且以后无法恢复它。你可以做一些丑陋的黑客攻击,但最好的方法是输入A

public interface TheClass<T> {
    public void theMethod(T obj);
}

public class A<T> {
    private TheClass<T> instance;

    public A(TheClass<T> instance) {
        this.instance = instance;
    }

    public void doIt(T target) {
        instance.theMethod(target); 
    }
}

它也不会破坏任何API。

答案 2 :(得分:1)

编译错误的 原因 ?通配符表示Java中的 unknown 类型。您可以使用未知的泛型参数声明变量,但不能实例化。这意味着您的构造函数中传入的泛型类可能已创建为包含与您稍后使用的内容不兼容的类型。一个很好的例子:

public class A {
    public static void main(String[] args) {
        TheClass<String> stringHolder = null; // should constrain parameters to strings
        A a = new A(stringHolder);
        a.donot(Float.valueOf(13)) ; // this is an example of what could happen
    }

    private TheClass<?> instance;

    public A(TheClass<?> instance) {
        this.instance = instance;
    }

    public void do(Object target) {
        instance.theMethod(target); 
    }
}

在这种情况下,编译器阻止您编写容易出错的代码。正如其他人所指出的那样,你应该为你的A类添加一个通用参数类型,以便约束允许的类型 - 这将消除编译时错误。

有人建议阅读:Oracle Generics Trail