Java泛型(4)通配符、上限通配符、下限通配符

1.官方文档

2.简介

2.1 通配符与通配符类型定义

List<?> list1;
List<? super Integer> list2;
List<? extends Number> list3;
  • 上面代码中的 ? 就是通配符,表示当前未知的泛型实参,该泛型实参由List<?>赋值时推断而来。如果该类型推断失败,该调用报错。如List.add(E),需要推断,而   List.add(null)和List.clear()等则无需类型推断。
  • ? super  Integer 通配符类型,限制泛型实参类型为Integer及其父类。
  • ? extends Number 是通配符类型,限制泛型实参为Number及子类型。

2.2 应用范围

可用范围

泛型形参 class A<? extends Number>{}
成员变量 List<?>  mData;
局部变量 Class<?> clazz;
函数形参

void foo(List<? extends Number> numbers){  }

void fun(List<? super Integer> numbers ){  }

返回值 List<? super Integer> foo() { return null; }
禁用范围 泛型形参声明

class A<? extends Number> {}  //error

class C<? super Integer> {  }    //error

泛型函数调用 this.<?>foo(2);      //error
泛型类实例创建 new B<?>();

示例如下:

public class Wildcards {
List<?> mData ; //成员变量
//class A<? extends Number> { } //error
//class B<? super Integer> { } //error
class C <T> { }
public List<? super Integer> foo() { return null; }
public <T> void foo(T t) { }
@Test
public void test1(){
this.<Float>foo(2f);
//this.<?>foo(2); //error
Class<?> clazz; //局部变量
C<?> objB = new C<>() ; //ok
//Object obj = new C<?>(); //error
}
}

2.3 通配符类型父子关系示例图

3.上限通配符

3.1 语法

? extends XXX ,XXX是类型 、接口 或 泛型类型,如

List<? extends Number> list1 //extends 类
List<? extends Serializable> list2 //extends 接口
List<? extends Comparable<Integer>> list3 //extends 泛型接口

注意 :

通配符上限与泛型形参的限定不一样,后者可以指定多个限定,而前者只能指定一个

@Test
public void wildcards_test4(){
class MyNumber extends Number implements Serializable,Comparable<MyNumber>{
@Override public int compareTo(MyNumber o) { return this.intValue() - o.intValue(); }
@Override public int intValue () { return 0; }
@Override public long longValue () { return 0; }
@Override public float floatValue () { return 0; }
@Override public double doubleValue () { return 0; }
}
class MyInteger extends Number{
@Override public int intValue () { return 0; }
@Override public long longValue () { return 0; }
@Override public float floatValue () { return 0; }
@Override public double doubleValue () { return 0; }
}
class MyByte extends Number implements Comparable{ //warning,raw type
@Override public int intValue () { return 0; }
@Override public long longValue () { return 0; }
@Override public float floatValue () { return 0; }
@Override public double doubleValue () { return 0; }
@Override public int compareTo(Object o) { return 1; } //这里意义,与Object比较
}
class MyFloat extends Number implements Comparable<Float>{ //warning,raw type
@Override public int intValue () { return 0; }
@Override public long longValue () { return 0; }
@Override public float floatValue () { return 0; }
@Override public double doubleValue () { return 0; }
@Override public int compareTo(Float o) { return floatValue() > o ? 1 : (floatValue() == 0 ? 0 : -1); }
}
//ArrayList<? extends Number & Serializable> ee; //error
class A <T extends Number & Serializable & Comparable<?>> {} //ok
class B <T extends Number & Serializable & Comparable<T>> {} //ok
class C <T extends Number & Serializable & Comparable > {} //warning,raw type
A<MyNumber> am = new A<>();
//B<String> bm = new B<>(); //error String 不是number
//C<MyInteger> cm = new C<>(); //error,MyInteger没有实现Comparable
C<MyByte> cb = new C<>(); //ok
C<MyFloat> cf = new C<>(); //ok
}

3.2 作用

  • 限制泛型实参的必需为xxx及其子类
  • 约定 List<? extends Number> 是 List<Integer>的父类,其它泛型类型同理,如Vector<? extends Number>是Vector<Float>父类。

3.3 示例

//Upper Bounded
public void process1(List<? extends Number> list) { //extends 类
for (Number elem : list) { /* */ }
}
@Test
public void test_upper_bounded (){
List<Number> list0 = new ArrayList<Byte>(); //error
List<Number> list1 = new ArrayList<>() ;
List<Integer> list2 = new ArrayList<>() ;
List<? extends Number> list3 = new ArrayList<Byte>();
List<Object> list4 = new ArrayList<>();
List<? extends Number> argument;
List<?> parent;
Object forefather;
argument = list0;
argument = list1;
argument = list4; //error : 泛型实参Object 是 Number父类
process1(list1);
process1(list2);
process1(list3);
process1(list4); //error : 泛型实参Object 是 Number的父类。
parent = argument; parent = list1 ; //...
forefather = parent ; forefather = argument; //...
}

3.4 ? extends 泛型类型

public void process4(List<? extends Comparable<Integer>> list) { //extends 接口
for (Comparable<Integer> s : list){
}
}
public void process5(List<? extends Comparable<?>> list) { //extends 接口
for (Comparable<?> s : list){
}
}
public void process6(List<? extends Comparable> list) { //extends 接口
for (Comparable s : list){
}
}
@Test
public void wildcards_test3(){
}

4. 未限定的通配符

4.1 作用

        在定义泛型类型时,如果只用一个?表示泛型实参。这就是未限定通配符.如: List<?> list; 它是其它List<XXX>的父类,是Object的子类。

4.2 示例

public void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}
@Test
public void wildcards_test5(){
List<Integer> listInt = Arrays.asList(1,2,3);
List<String> listStr = Arrays.asList("a","b","c");
Object obj = listInt;
List<?> list1 = listInt;
List<?> list2 = listStr;
obj = list1;
obj = list2;
printList(listInt);
printList(listStr);
printList(list1 );
printList(list2 );
}

结果

1 2 3 
a b c 
1 2 3 
a b c 

4.3 List<?>与List<Object> 区别

List<?>只能add(null),而List<Object>可add(Object及其子类)。

@Test
public void wildcards_test6(){
ArrayList<Integer> tmp = new ArrayList<>();
List<?> list1 = tmp;
List<?> list2 = Arrays.asList(1,2,3);
List<Object> list3 = Arrays.asList("a","b","c");
Object obj1 = list1;
Object obj2 = list3;
tmp.add(1) ; //ok
tmp.add(2) ; //ok
//list1.add(3) ; //error ,incompatible types: int cannot be converted to CAP#1
out.println(ClassLayout.parseInstance(tmp).toPrintable());
list1.add(null) ; //ok
list1.add(null) ; //ok
list1.add(null) ; //ok
list1.add(null) ; //ok
list1.add(null) ; //ok
list1.add(null) ; //ok
list1.add(null) ; //ok
list1.add(null) ; //ok
list1.add(null) ; //ok
//list1 = list3; //ok
out.println(ClassLayout.parseInstance(list1).toPrintable());
list1.clear() ; //ok
list3.add(1) ; //error,运行时错误。UnsupportedOperationException
list3.add(3f) ; //error,运行时错误。UnsupportedOperationException
list3.add(null) ; //error,运行时错误。UnsupportedOperationException
list3.clear() ; //error,运行时错误。UnsupportedOperationException
}

结果:

java.util.ArrayList object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0d 00 00 00 (00001101 00000000 00000000 00000000) (13)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 57 60 00 20 (01010111 01100000 00000000 00100000) (536895575)
12 4 int AbstractList.modCount 2
16 4 int ArrayList.size 2
20 4 java.lang.Object[] ArrayList.elementData [1, 2, null, null, null, null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
java.util.ArrayList object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0d 00 00 00 (00001101 00000000 00000000 00000000) (13)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 57 60 00 20 (01010111 01100000 00000000 00100000) (536895575)
12 4 int AbstractList.modCount 11
16 4 int ArrayList.size 11
20 4 java.lang.Object[] ArrayList.elementData [1, 2, null, null, null, null, null, null, null, null, null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
java.lang.UnsupportedOperationException
at java.base/java.util.AbstractList.add(AbstractList.java:153)
at java.base/java.util.AbstractList.add(AbstractList.java:111)
at com.example.sjjg.java.generic.Wildcards.wildcards_test6(Wildcards.java:178)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)

5.下限通配符

5.1 语法

?  super  xxx  , xxx为类型、接口、泛型类型,如下:

List<? super Integer> list5 = new ArrayList<Number>();
List<? super Number> list6 = new ArrayList<>();
List<? super Object> list7 = new ArrayList<>();
List<? super A<Integer>> list1 = new ArrayList<>();
List<? super A<E> > list2 = new ArrayList<>();

5.2 作用

  • 限定泛型实参的类型为xx及其父类。
  • 让List<? super Integer> 成为 List<Object>,List<Number>的父类。

5.3 示例

//Lower Bounded
private void foo_lower(List<? super Number> list){
//? super Number 限制传进来的类型一定是 List<Object>,List<Number> 其中 之一
list.add(0) ; //ok
list.add(1f) ; //ok
list.add(2L) ; //ok
list.add(3) ; //ok
list.add("4") ; //error : List<Object>可以add(String),但是List<Number>无法add(String)
list.add(new Object()) ; //error : List<Object>可以add(Object),但是List<Number>无法add(Object)
List<Object> ll = new ArrayList<>();
ll.add("eee");
Integer elem0 = (Integer) list.get(0) ;
int elem1 = (int) list.get(1) ;
Object elem2 = list.get(2) ;
Number elem3 = (Number) list.get(3) ;
out.println(String.format("elem0 = %s,elem1 = %s,elem2 = %s,elem3 = %s",elem0,elem1,elem2,elem3));
}
@Test
public <T> void lower_bounded1(){
List<Integer> list1 = new ArrayList<>();
List<Number> list2 = new ArrayList<>();
List<Object> list3 = new ArrayList<>();
List<String> list4 = new ArrayList<>();
List<? super Integer> list5 = new ArrayList<Number>();//虽然实际new 的是 ArrayList<Number>
List<? super Number> list6 = new ArrayList<>();
List<? super Object> list7 = new ArrayList<>();
List<? extends Number> list8 = new ArrayList<>();
List<?> parent ;
Object forefather ;
List<? super Number> argument ;
argument = new ArrayList<Integer>(); //error : 泛型实参为Integer
argument = new ArrayList<Number>() ;
argument = new ArrayList<Object>() ;
argument = new ArrayList<String>() ; //error : 泛型实参实参为String
argument = new ArrayList<T>() ; //error : T为不确定
argument = list1; //error : 泛型实参为Integer
argument = list2;
argument = list3;
argument = list4; //error : 泛型实参实参为String
argument = list5; //error : 泛型实参实参可能为Integer,list5 = argument; //ok
argument = list6;
argument = list7;
argument = list8; //error : 泛型实参实参为Number及子类。
foo_lower(list1); //error : 泛型实参为integer不是Number及其父类
foo_lower(list2); //ok
foo_lower(list3); //ok
foo_lower(list4); //error : 泛型实参String 不是Number及其父类
foo_lower(list5); //error : ? super Integer 不完全保证是泛型实参是Number,比如Integer就不是
foo_lower(list6); //ok
foo_lower(list7); //ok
foo_lower(list8); //error : ? extends Number 无法保证是泛型实参是Number,比如Float就不是
// List<?> 是List<xxx>父类 Object是所有类父类。
parent = list1 ; parent = list2; /*...*/ parent = list8; //ok
forefather = parent; forefather = list1; /*...*/ forefather = list8; //ok
}

5.4  ? super 泛型类型<T>

@Test
public <E> void lower_bounded2(){
class A <T> { }
List<? super A<Integer>> list1 = new ArrayList<>();
List<? super A<E>> list2 = new ArrayList<>();
}

6.通配符类型提取

6.1 通配符提取

        In some cases, the compiler infers the type of a wildcard. For example, a list may be defined as List<?> but, when evaluating an expression, the compiler infers a particular type from the code. This scenario is known as wildcard capture.

        带有 ? 的泛型实参由赋值时推断而来。如果该类型推断失败,该调用报错。

        ?extends Number 确保泛型实参一定是Number及其子类,但无法确定是哪一个子类,示例如下:

private void upper(List<? extends Number> list){
Object obj = list.get(0); //ok get(int) 不需要泛型类型E
list.set(0,100f) ; //error set(int,E) 需要泛型实参
list.remove(0) ; //ok remove(int) 不需要泛型类型E
list.clear() ; //ok clear() 不需要泛型类型E
list.add(0) ; //error add(E) 需要泛型类型E,这里推断失败
list.add(null) ; //ok add(null) 不需要泛型类型E
if(list.contains("aa")){ //ok contains(Object) 不需要泛型类型E
}
}

? super Integer 可以确保推断出来 泛型实参一定是Integer及其父类,示例如下:

private void lower(List<? super Integer> list){
Object obj = list.get(0); //ok get(int) 不需要泛型类型E
list.set(0,1) ; //ok set(int,E) 1,ok
list.set(0,1f) ; //error set(int,E) 1f是对应Float,不是Integer及其父类
list.remove(0) ; //ok remove(int) 不需要泛型类型E
list.clear() ; //ok clear() 不需要泛型类型E
list.add(0) ; //ok add(E) Integer
list.add(null) ; //ok add(null) 需要泛型类型E,这里推断失败
if(list.contains("aa")){ //ok contains(Object) 不需要泛型类型E
}
}

6.2 通配符的help函数

public class WildcardFixed {
void foo(List<?> i) {
fooHelper(i);
}
// Helper method created so that the wildcard can be captured
// through type inference.
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}
}

 

posted @   f9q  阅读(1268)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示