JAVA 泛型的使用(别特喵的花里胡哨逼逼一大堆,简单地说)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38292691/article/details/88862920

此文目录:

  1. Java泛型是什么?
  2. 通常的泛型的写法示例
  3. 类型擦除
  4. 为什么要使用Java泛型
  5. 通过示例了解PECS原则

一、Java泛型是什么?

泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

二、通常的泛型写法示例

  • T 类型,用于泛型类或者泛型方法

泛型类定义:

@Data
public class Result<T> {

       int     resultCode;
       String  resultMsg;
       T       resultObject;    
}

定义泛型方法:

public class JsonUtil {
    
    public <T> T  str2Json(String jsonText,Class target){
        T result=null;
        //....parse to json 
        return result;
    }

    public <T> T str2Json(String jsonText, Class<T> clazz) {
        T result = null;
        //....parse to json
        return result;
    }

    public static void main(String[] args) {
        Team team = new Team();
        Team t = team.str2Json("{}", Team.class);
        System.out.println(JSON.toJSONString(t));
    }
}
  •  K,V类型,类似Map接口。

public class ResultMap<K,V> {

    private K key;
    private V value;
    
   //省略 set ,get  方法


    public void put(K key,V value){
        this.key=key;
        this.value=value;
    }
}
  • ?extends 类型

<? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类
  • ?supper 类型

<? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型的超类型(父类型),直至Object

三、类型擦除

public class Operate {

    public static void main(String[] args) {

        List<String> names=new ArrayList<String>();
        names.add("Jack");
        names.add("Tom");
        names.add("peter");
        for(String name:names){
            System.out.println("wellcome:"+name);
        }
    }

}

使用java-gui反编译.exe  查看编译之后的代码如下

发现没有,根本没有<String> 这一部分了。这个限制为String类型的泛型被“擦除”了。写代码的时候,泛型会做校验,类型不对应的,无法add,但是编译之后边去掉了泛型类型。

 四、什么要使用Java泛型

在上面 第三部分介绍了“类型擦除”之后,在来说为什么要使用Java泛型就比较好说了。这里的泛型就相当于“约法三章”,先给你定好“规矩”,我这个List<String> 就是用来操作

String类型的,你插入Person对象就不行。说白了就是为了类型安全。所以其好处有:

  类型安全:通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

//该代码不使用泛型:
List li = new ArrayList();
li.put(new Integer(3));
Integer i = (Integer) li.get(0);


//该代码使用泛型:
List<Integer> li = new ArrayList<Integer>();
li.put(new Integer(3));
Integer i = li.get(0);

五、PECS原则

此处定义三个类,spring,summer继承season
public class Season {
  //.....  
}

public class Spring extends Season {
  //......  
}

public class Summer extends Season {
 //.......
}
        List<? extends Season> list1=new ArrayList<>();
        //list1.add(new Spring());//这里编译不通过,因为编译器无法确定list所持有的类型。
        List<? extends Season> list2=new ArrayList<Spring>();
//      list2.add(new Spring());//也是无法通过编译
     //通过上文,我们知道 ?extends Season表示可以接收的类型为 Seaon 或者其子类。
        但是此处不行,因为可能传入进来的是spring,或者summer,编译器无法确定具体传递进来的是什么,
        所以无法安全的向其中添加对象,但是它可以接收子类类型 的赋值。如下:

//
        List<Spring> list3=new ArrayList<Spring>();
        List<? extends Season> list4=list3;//这里和上面的list2做对比,无法直接add spring类型的对象
                                           //但是可以直接将spring类型的list赋值。
        
        List<Season> seasons=new ArrayList<Season>();
        List<? super Spring> spring=seasons;
        spring.add(new Spring());//ok
//      spring.add(new Summer());//error
//      spring.add(new Season());//error
//      spring.add(new Object());//error
        List<? super Season> sea=new ArrayList<>();
        sea.add(new Spring());//ok
        sea.add(new Summer());//ok
        sea.add(new Season());//ok
//      sea.add(new Object());//error
        
        List<? super Spring> spring=new ArrayList<>();
        spring.add(new Spring());//ok
//      spring.add(new Summer());//error
//      spring.add(new Season());//error
//      spring.add(new Object());//error

PECS原则 如下:

如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends)
如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)
如果既要存又要取,那么就不要使用任何通配符。

此文转自:http://www.cnblogs.com/demingblog/p/5495610.html

猜你喜欢

转载自blog.csdn.net/qq_38292691/article/details/88862920