zoukankan      html  css  js  c++  java
  • java泛型III-通配符

    通配符 — 使用一个奇怪的问号表示类型参数 — 是一种表示未知类型的类型约束的方法。通配符在类型系统中具有重要的意义,它们为一个泛型类所指定的类型集合提供了一个有用的类型范围。
    介绍通配符的使用前先定义几个类:

    public class Person {
    	private String name;
    	public Person(String name)
    	{
    		this.name=name;
    	}
    	
    	public void welcome()
    	{
    		System.out.println("@欢迎来到地球@");
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
        
    }
    
    
    public class Boy extends Person{
    
    	public Boy(String name) {
    		super(name);
    		// TODO Auto-generated constructor stub
    	}
        
    	public void genger()
    	{
    		System.out.println(getName()+":你是男孩子群体");
    	}
    }
    
    public class Gril extends Person{
    
    	public Gril(String name) {
    		super(name);
    		// TODO Auto-generated constructor stub
    	}
    
    	public void gender()
    	{
    		System.out.println(getName()+":你是女孩子群体");
    	}
    }
    
    public class Woman extends Gril {
    
    	public Woman(String name) {
    		super(name);
    		// TODO Auto-generated constructor stub
    	}
       
    	public void doWork()
    	{
    		System.out.println(getName()+":需要做家务!");
    	}
    }
    
    public class PersonUtil {
    	public void act(List<Person> list)
    	{
    		for(Person p:list)
    		{
    			p.welcome();
    		}
    	}
    }
    

    首先我们不用通配符,测试端:

    import java.util.ArrayList;
    import java.util.List;
    
    public class test3 {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
         PersonUtil personUtil=new PersonUtil();
         //测试1
         List<Person> persons=new ArrayList<>();
         persons.add(new Boy("wangqiang"));
         persons.add(new Gril("xiaofang"));
         personUtil.act(persons);
         //测试2
         List<Boy> persons1=new ArrayList<>();
         persons1.add(new Boy("wangqiang"));
         persons1.add(new Boy("xiaofang"));
         personUtil.act(persons1);
    	}
    }
    

    我们发现测试1顺利通过,而测试2编译不通过报错如下:

    Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    	The method act(List<Person>) in the type PersonUtil is not applicable for the arguments (List<Boy>)
    	at com.csu.fanxing.test3.main(test3.java:20)
    

    经过分析发现:act方法中是List,而测试2中是List,然而它们之间并不是父类与子类的关系,因此无法编译。

    1:通配符的上界

    格式:<?extends 类名>
    上述问题中List不是List的子类,那就需要寻找其它解决方案,是act方法更加通用。java中的解决方案就是是用通配符?,我们来改进act 方法。

    public void act1(List<? extends Person> list)
    	{
    		for(Person p:list)
    		{
    			p.welcome();
    		}
    	}
    

    然后继续运行测试2,发现正确通过。经过分析发现,List和List都是List<? extends Person>的子类,即通配符的上界就是它的子类均能编译通过。

    特别注意:

    public void add(List<?extends Person> list)
    	{
    		list.add(new Person("zhang"));//1
    		list.add(new Boy("shen"));//2
    	    list.add(new Girl("hu"));//3
    	}
    

    该段代码编译出错,为什么呢?我们来分析下:List<?extends Person> 类型是无法确定的,有可能是Person、Boy、Girl等。
    假设1:如果类型为Person,那么上段代码1,2,3都能添加成功。
    假设2:如果类型为Boy,那么上段代码只能成功添加2,1和3则无法添加。这就是为了保护类型的一致性。
    但是,上述list可以添加null,即:list.add(null); 是正确的。

    2:通配符下界

    格式:<?super 类名>
    其中该类就是下界,该类的父类均能编译通过。

    public void add(List<? super Gril> list)
    	{
    	    list.add(new Gril("hu"));
    	    list.add(new Woman("hua"));
    	}
    

    大家分析看这段代码:编译是通过的,为什么呢?
    因为List<? super Gril> 有两种基本类型即:List、List,我们可以把gril和woman看作是Person的对象,也可以看作是Gril的对象,因此不管是哪一个类型,两者均可以保持类型的一致性,所以编译没有报错。
    我们再看下下边实例:

     List<?super Gril> list=new ArrayList<>();
         list.add(new Gril("zhanghua"));//1
         list.add(new Woman("wangxia"));//2
         list.add(new Person("zhangsan"));//3
    

    发现代码3无法编译通过,原因和上边一样,Person对象不能作为Gril的对象,不能保持类型的一致性,所以报错。

    3:无界通配符

    知道了通配符的上界和下界,其实也等同于知道了无界通配符,不加任何修饰即可,单独一个“?”。如List<?>,“?”可以代表任意类型,“任意”也就是未知类型。
    格式:<?>
    1、当方法是使用原始的Object类型作为参数时,可以使用:

    public static void printList(List<Object> list) {
        for (Object elem : list)
            System.out.println(elem + "");
        System.out.println();
    }
    可以选择改为如下实现:
    
    public static void printList(List<?> list) {
        for (Object elem: list)
            System.out.print(elem + "");
        System.out.println();
    }
    

    2、在定义的方法体的业务逻辑与泛型类型无关,如List.size,List.clear。实际上,最常用的就是Class<?>,因为Class并没有依赖于T。

    4:通配符捕捉

    通配符不是类型变量,因此不能在编写代码中使用“?“作为一种类型。我们可以通过“捕捉助手“来解决这个问题。

    public void rebox(Box<?> box) {
        reboxHelper(box);
    }
    
    private<V> void reboxHelper(Box<V> box) {
        box.put(box.get());
    }
    

    助手方法 reboxHelper() 是一个泛型方法, 泛型方法引入了额外的类型参数(位于返回类型之前的尖括号中),这些参数用于表示参数和/或方法的返回值之间的类型约束。然而就 reboxHelper() 来说,泛型方法并不使用类型参数指定类型约束,它允许编译器(通过类型接口)对 box 类型的类型参数命名。

    引用块内容
    http://www.ibm.com/developerworks/cn/java/j-jtp04298.html
    http://www.linuxidc.com/Linux/2013-10/90928.htm
    java核心技术 卷I

  • 相关阅读:
    [Node.js] CommonJS Modules
    [Node.js] npm init && npm install
    [AngularJS] Hijacking Existing HTML Attributes with Angular Directives
    [Node.js] Level 7. Persisting Data
    [Express] Level 5: Route file
    [Express] Level 5: Route Instance -- refactor the code
    [Express] Level 4: Body-parser -- Delete
    [Express] Level 4: Body-parser -- Post
    [Express] Level 3: Massaging User Data
    [Express] Level 3: Reading from the URL
  • 原文地址:https://www.cnblogs.com/csuwater/p/5399347.html
Copyright © 2011-2022 走看看