泛型:如何捕获通配符?

时间:2015-07-16 12:45:31

标签: java generics

不,这个问题不是关于它们之间的区别吗?和T;这是关于我如何转向< ? >参数命名为< T>。 请考虑以下示例代码:

import java.io.Serializable;

class A<T extends Serializable> {
    <S extends Serializable> void bar(S arg) { }
    void bar2(T arg) { }
}

public class B {
    A<? extends Serializable> myA = null;    
    <T extends Serializable> void foo(T arg) {
        myA.bar(arg);
        myA.bar2(arg);
    }
}

我的问题是以上事实并没有编译;对bar2()的调用给了我

The method bar2(capture#2-of ? extends Serializable) in the type
A<capture#2-of ? extends Serializable> is not applicable for the arguments (T)

我想&#34;原因&#34;因为那是myA是&lt; ?扩展Serializable&gt; ;但B.foo中的T ......很好,一个名叫T;而不是通配符?。

解决问题的一种方法&#34;这将是&lt; T扩展了Serializable&gt; 类B的类型参数......但这基本上与我对该类的其他用法冲突。含义:我最终写下了B及其成员myA,这完全是因为我不想参数化B类。所以,我开始只使用bar2()方法;然后在以后添加了bar()......但这并没有真正帮助。

那么 - 有没有办法让我的班级B使用A.bar2()作为&#34;意图&#34;在我的示例代码中?

编辑:而且确切地说 - bar()方法对我没有帮助;作为&#34; S&#34;那里......并不与&#34; T&#34;我真正在A班使用。

2 个答案:

答案 0 :(得分:2)

你走到了尽头。

A<? extends Serializable> myA = ...;

所以myA是未知的A。它可以是A<String>,也可以是A<Integer>A<Banana>。你只是不知道。我们假设它是A<Banana>

<T extends Serializable> void foo(T arg) {

所以foo()接受任何可序列化的:String,Integer,Banana,Apple,等等。假设它以Integer作为参数调用。

myA.bar2(arg);

因此,基于上述假设,虽然bar2()myA,但会以{\ n}为参数调用A<Banana>。编译器无法接受这一点:它显然不是类型安全的。 B必须是通用的。

答案 1 :(得分:1)

@JBNizet已经解释了为什么不能这样做。这个答案旨在解释你可能有的选择(在你的问题中正确地指出了其中一个,但这不是唯一的选择)。

让B采用类型参数

class B<T extends Serializable> {

    A<T> myA = null;    

    void foo(T arg) {
        myA.bar(arg);
        myA.bar2(arg);
    }
}

使B从A延伸(如果B通过A的a-a测试)

class B extends A<String> {

    public void foo(String arg) {
        bar2(arg);
        bar(1);
    }
}

两个选项之间的区别在于:1)barbar2都需要传递相同的类型,其中2 barbar2可以传递不同的类型,因为bar2由为A声明的类型参数绑定,其中bar由为方法声明的类型参数绑定。