当前位置: 首页 > 知识库问答 >
问题:

显式指定通配符的上限时是否有区别?

凌昕
2023-03-14
Generic<?>
Generic<? extends BaseType>
List<Generic<?>>
List<Generic<? extends BaseType>>

考虑到这一点,我会假设这些是等价的。generic指定类型参数A具有baseType作为上限。

因此,通配符应该始终由basetype“自动”或“隐式”限定,不管我是否显式指定它。

下面,我试图将我的陶醉与JLS协调起来。

>

  • D ,其中D 是泛型类型,它是泛型类型C 的直接超型,θ是替换[f1:=t1,...,fn:=tn]。

    C ,其中Si含有Ti(1≤i≤n)(§4.5.1)。

    (强调我的)

    据我所知,“通配符”在JLS中不被视为“类型”。因此,这不能应用于前两个示例,但可以应用于列表的两个示例。

    相反,这应该适用:

    由于1baseType,因此fresh变量的上限为baseType

    对于第二种情况,通过

    如果Ti是表单的通配符类型参数?扩展Bi,则Si是一个新的类型变量,其上界为glb(Bi,UI[a1:=S1,...,an:=SN]),其下界为null类型。

    对于嵌套通配符,我将使用“contains”规则:

    一个类型参数T1被称为包含另一个类型参数T2,写为T2<=T1,如果由T2表示的类型集在以下规则的自反和传递闭包下是由T1表示的类型集的可证子集(其中<:表示子类型(§4.10)):

    >

  • ?扩展T<=?如果T<:S则扩展S

    <代码>?扩展T<=?

    <代码>?超级T<=?super S if S<:t

    结合

    C ,其中Si含有Ti(1≤i≤n)(§4.5.1)。

    从上面,我得到:

  • 共有1个答案

    习狐若
    2023-03-14

    从字面上理解您最初的问题,在generic<?>generic<之间“是否有显著的区别”?扩展basetype>,答案肯定是,它们不等价。

    JLS§4.5.1明确规定:

    通配符?扩展对象等效于无界通配符

    boolean b1 = new Object() instanceof Supplier<?>; // valid code
    boolean b2 = new Object() instanceof Supplier<? extends Object>; // invalid
    
    Supplier<?>[] array1; // valid declaration
    Supplier<? extends Object>[] array1; // invalid
    
    interface NumberSupplier<N extends Number> extends Supplier<N> {}
    

    我们可以写

    NumberSupplier<? extends Object> s1;
    NumberSupplier<? extends Serializable> s2;
    NumberSupplier<? extends BigInteger> s3;
    

    甚至

    NumberSupplier<? extends CharSequence> s4;
    

    我们甚至可以在没有实际类型的情况下实现它,使用()->null扩展numbercharsequence

    NumberSupplier<? extends String> s5;
    

    因此,如果我们有类似list > list > 列表 > ,并希望根据§4.5.1的contains规则(唯一可以应用的规则)来推断其中任何一个是否是其他类型的子类型,当类型参数是相同类型(t<=t)时,但是,我们不需要子类型规则,因为所有这些列表类型都是相同的类型:

    如果两个引用类型具有相同的二进制名称(§13.1),并且它们的类型参数(如果有的话)是相同的,则它们是相同的编译时类型,递归地应用这个定义。

    contains规则仍然很有用,例如,它允许推断映射 map 的子类型,因为对于第一个类型参数string<=string,第二个类型参数的类型参数由通配符特定的包含规则覆盖。

    所以剩下的问题是,哪个规则允许我们得出numbersuppliver<?>numbersuppliver<?扩展对象>NumberSupplier<?扩展number>是相同的类型,因此列表 > 列表 > 列表 > 是可相互分配的。

    它似乎不是捕获转换,因为捕获转换意味着计算有效的边界,但也为每个绝对是不同类型的通配符创建“新类型变量”。但是没有其他规则涵盖通配符兼容性。或者我没找到。尝试将规范与javac的实际行为相匹配,得到了一些非常有趣的结果:

    给定

    interface MySupplier<S extends CharSequence&Appendable> extends Supplier<S> {}
    
    List<MySupplier<? extends CharSequence>> list1 = Collections.emptyList();
    List<MySupplier<? extends Appendable>>   list2 = Collections.emptyList();
    
    list1 = list2; // compiler error
    list2 = list1; // dito
    

    尽管任何涉及捕获转换的操作确实会得出兼容的类型,例如。

    list1.set(0, list2.get(0)); // no problem
    list2.set(0, list1.get(0)); // no problem
    

    做被拒绝的作业间接起作用:

    List<MySupplier<?>> list3;
    list3 = list1;
    list2 = list3; // no problem
    // or
    list3 = list2;
    list1 = list3; // again no problem
    

    但是在这里,不等同于?扩展对象:

    List<MySupplier<? extends Object>> list4;
    list4 = list1; // compiler error
    list2 = list4; // dito
    // or
    list4 = list2; // dito
    list1 = list4; // dito
    
    list4 = list3 = list1; // works
    list1 = list3 = list4; // works
    list4 = list3 = list2; // works
    list2 = list3 = list4; // works
    
     类似资料:
    • 问题内容: 该问题的答案表明,当方法采用通配符通用类型时,可以访问或修改集合,但不能同时访问或修改集合。(凯西和伯特) 这是什么意思?“ 当方法采用通配符通用类型时,可以访问或修改集合,但不能同时访问两者 ”? 据我所知,方法do1具有d2只能访问但不能修改。d2的方法使c2可以被访问和修改,并且没有编译错误。 通用准则 问题答案: 该问题的答案表明,当方法采用通配符通用类型时,可以访问或修改集合

    • 问号(?)代表通配符,代表泛型中的未知类型。 有时您可能希望限制允许传递给类型参数的类型。 例如,对数字进行操作的方法可能只想接受Number或其子类的实例。 要声明一个上限的Wildcard参数,请列出?,后跟extends关键字,后跟其上限。 例子 (Example) 以下示例说明了如何使用extends来指定上限通配符。 package com.wenjiangs; import java.

    • 类型参数T不应由最终的类型整数限定。不能进一步扩展Final类型 为什么使用final类型作为通配符的上限完全可以,但对类型参数抛出警告?为什么Java甚至允许通配符被最终的上层类型所约束?

    • 问题内容: 有没有一种方法可以使用querySelector或进行通配符元素名称匹配querySelectorAll?我看到属性查询中支持通配符,但不支持元素本身。 我要解析的XML文档基本上是一个简单的属性列表,我需要查找名称中包含某些字符串的元素。 我意识到,如果我需要的话,XML文档可能需要进行重组,但这不会发生。 除了返回使用显然不推荐使用的XPath(IE9删除了它)之外,任何解决方案都

    • 我的问题是,如果我的进程(在linux机器上)需要更多的5 GB(我有30 GB RAM),当我没有指定任何显式堆大小(Xms和Xmx)参数时,我的进程是否会被分配5 GB内存。

    • 这个问题的答案表明,当方法采用通配符泛型类型时,可以访问或修改集合,但不能同时访问或修改集合。(凯西和伯特) 据我所知,方法do1有,因此d2只能被访问,不能被修改。方法d2具有,因此可以访问和修改c2,并且没有编译错误。 通用指南