java泛型类&通配符

时间:2015-07-10 19:26:07

标签: java generics

我有一个具有以下功能的Box泛型类:

  • 2个put方法中的一个应该允许客户端插入一个框并将其内容发送到当前框。

我希望此方法能够获得两种类型的框:Box<Number>Box<Integer>,这就是我将put(Box<T>)方法更改为put(Box<? extends Number> box)的原因。但是我收到了编译警告。我在这做错了什么?

这是我目前的代码: 我得到的警告是:类型安全:未捕获来自捕获#1​​的投射?将Number扩展为T

public class Box<T> {
    public T get() {
        return element;
    }

    public void put(T element) {
        this.element = element;
    }

    public void put(Box<? extends Number> box) {
        put((T) box.get()); // this is where i get the warning
    }

    private T element;
}

public class BoxClient {

    public static void main(String[] args) {
        Box<Number> nBox = new Box<Number>();
        Box<Integer> iBox = new Box<Integer>();
        nBox.put(iBox);

    }

}

5 个答案:

答案 0 :(得分:6)

将其更改为

public void put(Box<? extends T> box) {
    put(box.get());
}

答案 1 :(得分:3)

如果我测试你的代码,那么我会在这个方法中收到警告:

public void put(Box<? extends Number> box) {
    put( (T) box.get());
}

警告是:

  

未选中广告:java.lang.NumberT

问题是您的通用类型T没有bounds,因此它可以是任何内容,由于type erasure它将被删除为Object

变量box的泛型类型有一个界限,很明显,它总是某种Number

您的广告(T) box.get()现在“不安全”,因为box.get()返回的子类型为NumberT可以是任何内容,例如String。因此编译无法确定此强制转换是否总是正常并且不会抛出ClassCastException。 这就是他警告你不安全演员的原因。

答案 2 :(得分:1)

你的Box有一个通用类型T,它不对它的类型做任何假设(没有界限)。如果您的框只能包含Number s(以及Number的子类型),则可以将其更改为:class Box<T extends Number>。 和您的方法:put(Box<? extends T> box),以便它接受T及其任何子类型。

答案 3 :(得分:1)

您的班级Box定义了通用类型TT可以是任何东西。即“包含任何种类对象”的框

然后,您的方法会收到Box<? extends Number>。即“包含数字类型的框”。

问题在于你的方法:

public void put(Box<? extends Number> box) {
    put(box.get());
}

该方法接收“包含数字的方框”,但是,它会转换为T。 请记住,T可以是任何内容,因此您可以对某些实际上不是数字的内容执行强制转换。考虑这个例子:

public class BoxClient {

    public static void main(String[] args) {
        Box<String> sBox = new Box<String>();
        Box<Integer> iBox = new Box<Integer>();

        iBox.put(1);
        sBox.put(iBox);

        System.out.println(sBox.get()); 
    } 

}

在这里,我创建了一个Box<String>或“一个包含字符串的框”,并添加了一个Box<Integer>或“一个包含数字的框”。 通过泛型代码,这是有效的,因为T可以是任何东西,但是,如果你试图执行它

  

java.lang.ClassCastException:java.lang.Integer无法强制转换为java.lang.String

那是因为Integer 1无法转换为String

为了确保永远不会发生这种情况,您需要更改Box的声明以强制执行T extends Number,如下所示:

public class Box<T extends Number> {
    public T get() {
        return element;
    } 

    public void put(T element) {
        this.element = element;
    }

    public void put(Box<? extends T> box) {
        put((T) box.get());
    }

    private T element;
}

更新: 如上所述,我之前的回答可能仍然不安全。 比如说,如果你有一个Box<Number>并尝试添加Box<Integer>,它仍然会被允许并仍然会抛出异常。

最佳解决方案是添加bayou.io的建议。 这样你就可以确保: 1:您的Box总是包含数字 2:您的Box只能从T

延伸的其他Box添加

UPDATE2: 正如下面newacct的评论所述,对T的强制转换也没有必要。

希望这有帮助!

答案 4 :(得分:0)

您的问题导致事实,即Java 5中引入了泛型类型。因此,方法签名不包含有关的信息。 通用类。

课程草稿:

public abstract class Draft<T> {
    public abstract void put(T element);
    public abstract void putDraft(Draft draft);
}

使用此草案,代码保持可读性,您没有任何编译器 警告。

查看here以查找有关此问题的更多信息。