Java 泛型学习三 通配符

Java 泛型学习一 泛型概念
Java 泛型学习二 泛型的限制
Java 泛型学习三 通配符
Java 泛型学习四 自动擦除
Java 泛型学习五 泛型擦除带来的不自然
Java 泛型学习六 泛型类型系统

什么是泛型通配符

我们来看看泛型的类型变量的继承吧,按照常规的继承理解,下面代码应该是没问题的:

package net.oseye;

import java.util.ArrayList;
public class FanXing {
	public static void main(String[] args) {
		ArrayList<String> as=new ArrayList<String>();
		ArrayList<Object> ao=null;
		ao=as;
	}
}

因为任何类都继承自Object类,但却不能通过编译:

net\oseye\FanXing.java:9: 错误: 不兼容的类型
                ao=as;
                   ^
  需要: ArrayList<Object>
  找到:    ArrayList<String>
1 个错误

可以总结出若A是B的子类,则G<A>可以当做G<B>使用并不成立。

如果想要达到目的就要使用通配符“?”,通配符“?”代表任意具体类型,如上述代码改成:

package net.oseye;

import java.util.ArrayList;
public class FanXing {
	public static void main(String[] args) {
		ArrayList<String> as=new ArrayList<String>();
		ArrayList<?> ao=null;
		ao=as;
	}
}

就可以编译通过。


使用泛型通配符注意事项:


  1. 泛型通配符只能用于引用的声明中,不可以在创建对象时使用;
    package net.oseye;
    
    public class FanXing {
    	public static void main(String[] args) {
    		Fruit<?> fruit=new Fruit<?>();
    	}
    }
    
    class Fruit<T>{
    	private T color;
    	public void setColor(T color){
    		this.color=color;		
    	}
    	public String getColor(){
    		return this.color.toString();		
    	}
    }
    上述代码是编译不通过的,异常:
    net\oseye\FanXing.java:5: 错误: 意外的类型
                    Fruit<?> fruit=new Fruit<?>();
                                            ^
      需要: 不带限制范围的类或接口
      找到:    ?
    1 个错误
    
  2. 不可以使用采用了泛型通配符的引用调用使用了泛型参数的方法;
    package net.oseye;
    
    public class FanXing {
    	public static void main(String[] args) {
    		Fruit<?> fruit=new Fruit<String>();
    		fruit.setColor("red");
    	}
    }
    
    class Fruit<T>{
    	private T color;
    	public void setColor(T color){
    		this.color=color;		
    	}
    	public String getColor(){
    		return this.color.toString();		
    	}
    }
    上述代码也不能通过编译,异常:
    net\oseye\FanXing.java:6: 错误: 无法将类 Fruit<T>中的方法 setColor应用到给定类型
    ;
                    fruit.setColor("red");
                         ^
      需要: CAP#1
      找到: String
      原因: 无法通过方法调用转换将实际参数String转换为CAP#1
      其中, T是类型变量:
        T扩展已在类 Fruit中声明的Object
      其中, CAP#1是新类型变量:
        CAP#1从?的捕获扩展Object
    1 个错误
    
  3. 通配符也可以限制的,语法:? extends 类名或接口名
    package net.oseye;
    
    public class FanXing {
    	public static void main(String[] args) {
    		Apple<String> appleStr=new Apple<String>();
    		appleStr.setColor("红色");
    		
    		Apple<Integer> appleNum=new Apple<Integer>();
    		appleNum.setColor(1);
    		
    		SayColor(appleStr);
    		SayColor(appleNum);
    	}
    	
    	static void SayColor(Apple<? extends String> apple){
    				System.out.println(apple.getColor());
    	}
    }
    
    class Apple<T>{
    	private T color;
    	public void setColor(T color){
    		this.color=color;		
    	}
    	public T getColor(){
    		return this.color;		
    	}
    }
    异常信息可以看得出限制起到了作用:
    net\oseye\FanXing.java:12: 错误: 无法将类 FanXing中的方法 SayColor应用到给定类型
    ;
                    SayColor(appleNum);
                    ^
      需要: Apple<? extends String>
      找到: Apple<Integer>
      原因: 无法通过方法调用转换将实际参数Apple<Integer>转换为Apple<? extends String
    >
    1 个错误
原文地址:https://www.cnblogs.com/zhaiqianfeng/p/4618362.html