简体   繁体   English

泛型和正确类型的转换

[英]Generics and casting to the right type

My problem can be summed-up by this snippet: 我的问题可以通过以下代码段总结:

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.
    }
}

My class A uses an instance of TheClass with its generics type unknown. 我的类A使用TheClass的实例,其泛型类型未知。 It features a method with a target passed as Object since the TheClass instance can be parameterized with any class. 它具有一个以目标作为Object传递的方法,因为TheClass实例可以用任何类进行参数化。 However, the compiler won't allow me to pass the target like this, which is normal. 但是,编译器不允许我这样传递目标,这是正常的。

What should I do to circumvent this issue? 我应该怎么做才能避免这个问题?

A dirty solution is to declare the instance as TheClass<? super Object> 肮脏的解决方案是将实例声明为TheClass<? super Object> TheClass<? super Object> , which works fine but is semantically wrong... TheClass<? super Object> ,效果很好,但是在语义上是错误的...

Another solution I used before was to declare the instance as raw type, just TheClass , but it's bad practice, so I want to correct my mistake. 我之前使用的另一种解决方案是将实例声明为原始类型,仅是TheClass ,但这是一种不好的做法,因此我想纠正我的错误。

Solution

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); 
    }
}
public class A {
    private TheClass<Object> instance;

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

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

or 要么

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

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

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

The solution is to also type A . 解决方案是也键入A Using a wildcard ? 使用通配符? makes you loose the type information of TheClass and there is no way to recover it later. 使您失去TheClass的类型信息,并且以后无法恢复。 There are some ugly hacks you could do but your best shot is to also type A : 您可以执行一些丑陋的操作,但最好的方法是同时键入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); 
    }
}

It won't break any API either. 它也不会破坏任何API。

The reason for the compile error is that the ? 编译错误的原因? wildcard indicates the unknown type in Java. 通配符指示Java中的未知类型。 You may declare a variable with an unknown generic parameter, but you cannot instantiate one with it. 您可以使用未知的通用参数声明一个变量,但不能使用它实例化一个变量。 Which means that the in your constructor the passed in generic class could have been created to hold types that are incompatible with what you are trying to later on use. 这意味着可以在构造函数中创建传入的泛型类,以容纳与您稍后尝试使用的类型不兼容的类型。 Case in point: 例子:

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

In this case the compiler is preventing you from writing code that would have been prone to bugs. 在这种情况下,编译器将阻止您编写容易出错的代码。 As others have pointed out, you should add a generic parameter type to your A class, in order to constrain the allowed types - that will remove the compile time error. 正如其他人指出的那样,您应该在A类中添加通用参数类型,以限制允许的类型-这样可以消除编译时错误。

Some suggested reading: Oracle Generics Trail 建议阅读以下内容: Oracle Generics Trail

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM