标签: bounded-wildcard

为什么我不能使用通配符(?)作为参数,字段,局部变量的类型,或作为方法的返回类型?

关于泛型中的通配符的Oracle 文档说,

通配符可用于各种情况:作为参数,字段局部变量的类型 ; 有时作为返回类型 (虽然更好的编程实践更具体).

我在下面的类中尝试了所有四个,并且在每个类中都有编译器错误.为什么?我究竟做错了什么?

public class MainClass {
    private ? instanceFieldWithWildCardType;//ERROR
    private static ? staticFieldWithWildCardType;//ERROR

    private void methodWithWildCardParam(? param) {}//ERROR

    private void methodWithWildCardLocalVariable() {
        ? localVariableWithWildCardType;//ERROR
    }

    private ? methodWithWildCardReturnType() {//ERROR
        return null;
    }

    private void methodWithWildCardParam(? param) {}//ERROR

}
Run Code Online (Sandbox Code Playgroud)

java generics wildcard bounded-wildcard unbounded-wildcard

14
推荐指数
2
解决办法
3665
查看次数

使用generic来存储Java中的常用超类型

假设我有一个方法"mix",它采用两个可能不同类型的T和S列表,并返回一个包含两者元素的List.对于类型安全,我想指定返回的List是R类型,其中R是T和S共有的超类型.例如:

List<Number> foo = mix(
    Arrays.asList<Integer>(1, 2, 3),
    Arrays.asList<Double>(1.0, 2.0, 3.0)
);
Run Code Online (Sandbox Code Playgroud)

为了指定这个,我可以将方法声明为

static <R, T extends R, S extends R> List<R> mix(List<T> ts, List<S> ss)
Run Code Online (Sandbox Code Playgroud)

但是如果我想在类上创建mix一个实例方法而不是静态List2<T>呢?

<R, T extends R, S extends R> List<R> mix ...
Run Code Online (Sandbox Code Playgroud)

阴影<T>在实例上List2,所以没有好处.

<R, T extends S&T, S extends R> List<R> mix ...
Run Code Online (Sandbox Code Playgroud)

解决了阴影问题,但编译器不接受

<R super T, S extends R> List<R> mix ...
Run Code Online (Sandbox Code Playgroud)

被编译器拒绝,因为下限通配符不能存储在命名变量中(仅用于? super X表达式)

我可以将参数移动到类本身,例如List2<R, T extends R, S extends R>,但类型信息实际上没有业务存在于实例级别,因为它仅用于一个方法调用,并且您每次需要时都必须重新构建对象在不同的参数上调用该方法. …

java generics bounded-wildcard

13
推荐指数
1
解决办法
673
查看次数

为什么java.lang.Class的getInterfaces()方法返回Class <?> []而不是Class <?超级T> []?

(要清除问题,'T'指的是在Class中声明的类型参数)

举个例子,请查看以下应用程序:

public class TestClass {

    interface InterfaceA{}

    interface InterfaceB{}

    interface InterfaceC{}

    class ClassA implements InterfaceA, InterfaceB,  InterfaceC{}


    public static void main(String[] args){    

        Class<? super ClassA> superClass1 = ClassA.class;
        Class<? super ClassA> superclass2 = InterfaceA.class;
        Class<? super ClassA> superclass3 = InterfaceB.class;
        Class<? super ClassA> superclass4 = InterfaceC.class;

        for(Class<?> clazz : ClassA.class.getInterfaces()){
            System.out.println(clazz.getName());
        }   
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是人们所期望的:

TestClass$InterfaceA
TestClass$InterfaceB
TestClass$InterfaceC
Run Code Online (Sandbox Code Playgroud)

因此,基于上面的这个例子,我们可以看到编译器认识到InterfaceA 确实符合通配符的边界,所有其他接口也是如此.

直观地说,我希望以下是安全的,但它不是:

Class<? super ClassA>[] interfaces = ClassA.class.getInterfaces();
Run Code Online (Sandbox Code Playgroud)

编译器发出警告,因为签名表示它返回Class; 但是,Class的javadoc声明如下:

如果此对象表示类,则返回值是一个数组,其中包含表示该类实现的所有接口的对象.

'这个对象'在我们的例子中指的是ClassA.基于此声明,如果我们致电:

ClassA.class.getInterfaces()
Run Code Online (Sandbox Code Playgroud)

然后我们从逻辑上知道Class<?>返回数组中的每一个都将包含对超类型的引用ClassA …

java generics interface bounded-wildcard

12
推荐指数
1
解决办法
2139
查看次数

Java泛型:有界类型参数中的多重继承<T扩展A&I>

我即将创建一个工厂,它创建某种类型的对象T,它扩展了某个类A和另一个接口I.但是,T必须是未知的.以下是最低声明:

public class A { }
public interface I { }
Run Code Online (Sandbox Code Playgroud)

这是工厂方法:

public class F {
    public static <T extends A & I> T newThing() { /*...*/ }
}
Run Code Online (Sandbox Code Playgroud)

这编译所有罚款.

当我尝试使用该方法时,以下工作正常:

A $a = F.newThing();
Run Code Online (Sandbox Code Playgroud)

......虽然这不是:

I $i = F.newThing();
Run Code Online (Sandbox Code Playgroud)

编译器抱怨:

绑定不匹配:类型F的泛型方法newThing()不适用于arguments().推断的类型I和A不是有界参数的有效替代

我不明白为什么.明确指出"newThing返回某种类型的东西T,它确实扩展了A类并实现了接口I".当分配给一个一切正常(因为T延伸的),但分配给我并没有(因为什么?,清楚地返回的东西既是一个一个I)

另外:当返回一个对象时,比如说类型B class B extends A implements I,我需要将它转换为返回类型T,尽管B匹配边界:

<T extends A & I> T newThing() {
    return (T) new B();
}
Run Code Online (Sandbox Code Playgroud)

但是,编译器不会抛出任何警告,如UncheckedCast等.

因此我的问题:

  • 这里出了什么问题?
  • 是否容易实现所需的行为(即分配给静态类型A或I的变量),就像在工厂方法中通过强制转换解决返回类型问题一样?
  • 为什么分配到A工作,而我不工作?

-

编辑:这里完整的代码片段完全使用Eclipse 3.7,项目设置为JDK 6: …

java generics types bounded-wildcard

12
推荐指数
2
解决办法
2万
查看次数

使用通配符创建新的通用对象

请解释这个通用代码通配符编译时错误:

//no compile time error.
List<? extends Number> x = new ArrayList<>(); 

//compile time error.  
List<? extends Number> x = new ArrayList<? extends Number>();
Run Code Online (Sandbox Code Playgroud)

java generics bounded-wildcard

11
推荐指数
1
解决办法
3260
查看次数

较低有界通配符未针对上限有效类型参数进行检查

我想知道为什么这段代码编译成功?

源代码:

abstract class A<K extends Number>
{
    public abstract <M> A<? super M> useMe(A<? super M> k);
}
Run Code Online (Sandbox Code Playgroud)

编译成功

它是如何工作的,为什么编译?M是任何类型,为什么它可以使用?应该是:<M extends Number>?这不会编译:

abstract class A<K extends Number>
{
    public abstract <M> A<? super M> useMe(A<M> k);
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

类型参数M不在类型变量K的范围内,其中M,K是类型变量:M extends方法useMe中声明的Object(A)K extends A类中声明的Number

有什么不同?

java generics bounded-wildcard

11
推荐指数
2
解决办法
205
查看次数

Java泛型方法:超级不能用?

所以我有这个方法:

protected void collectSelectedItems(ListSelectionModel lsm, 
         Collection<? super MyItemClass> result) {
    for (int i : GUI.getSelectionIndices(lsm))
    {
        result.add(getItemByDisplayIndex(i));
    }
}
Run Code Online (Sandbox Code Playgroud)

我想返回集合而不是void方法:

protected <T super MyItemClass> Collection<T> 
  collectSelectedItems(ListSelectionModel lsm, Collection<T> result) {
    for (int i : GUI.getSelectionIndices(lsm))
    {
        result.add(getItemByDisplayIndex(i));
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

意图做这样的事情(在哪里MyItemClass extends MyItemBaseClass):

List<MyItemBaseClass> list = 
   collectSelectedItems(lsm, new ArrayList<MyItemBaseClass>());
Run Code Online (Sandbox Code Playgroud)

但我得到一个语法错误super:

令牌"super"上的语法错误,预期

是什么赋予了?我能解决这个问题吗?

java generics bounded-wildcard

10
推荐指数
1
解决办法
5654
查看次数

为什么这个通用赋值是非法的?

我有一堂课:

class Generic<T> {
    List<List<T>> getList() {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我Generic用通配符和调用getList方法声明 a时,以下赋值是非法的。

Generic<? extends Number> tt = null;
List<List<? extends Number>> list = tt.getList(); // this line gives compile error
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎很奇怪,因为根据 的声明Generic,很自然地创建 aGeneric<T>并获得 a List<List<T>>when call getList

事实上,它需要我像这样写作业:

List<? extends List<? extends Number>> list = tt.getList(); // this one is correct
Run Code Online (Sandbox Code Playgroud)

我想知道为什么第一个是非法的,为什么第二个是合法的。

我给出的例子只是一些示例代码来说明问题,您不必关心它们的含义。

错误信息:

不兼容的类型:
必需:List<java.util.List<? extends java.lang.Number>>
找到:List<java.util.List<capture<? extends java.lang.Number>>>

java generics bounded-wildcard

10
推荐指数
1
解决办法
296
查看次数

嵌套有界通配符

当我尝试编译以下代码时:

LinkedList<List<? extends Number>> numList = new LinkedList<List<Integer>>();
Run Code Online (Sandbox Code Playgroud)

我得到一个不兼容的类型错误:

Required: LinkedList <java.util.list<? extends java.lang.Number>>
Found: LinkedList <java.util.list<Integer>>
Run Code Online (Sandbox Code Playgroud)

如何实现LinkedList包含具有List扩展元素的元素Number

为了清楚起见,我希望以numList下列方式添加列表:

numList.add(new LinkedList<Integer>());

java generics bounded-wildcard

9
推荐指数
1
解决办法
188
查看次数

创建无界和有界外卡类型数组之间的区别?

为什么这段代码有效

ArrayList<?>[] arr = new ArrayList<?>[2];
Run Code Online (Sandbox Code Playgroud)

但以下两个不是?

ArrayList<? extends Object>[] arr = new ArrayList<? extends Object>[2];
ArrayList<? super Object>[] arr = new ArrayList<? super Object>[2];
Run Code Online (Sandbox Code Playgroud)

最后两行生成编译错误;

错误:通用数组创建.

请澄清差异.

更新

另一方面ArrayList<?>[] arr = new ArrayList<?>[2];编译好但是

ArrayList<?> arr = new ArrayList<?>();
Run Code Online (Sandbox Code Playgroud)

不.

java arrays generics wildcard bounded-wildcard

9
推荐指数
1
解决办法
1156
查看次数