简明 Java 泛型

用简单明了的文字, 记录认知.

目录

  • 一、概述
  • 二、作用
    • 2.1 语法糖
    • 2.2 类型擦除
  • 三、使用方法
    • 3.1 泛型定义
    • 3.2 泛型标识(通配符)
      • 3.2.1 约定通配符
      • 3.2.2 上限通配符
      • 3.2.3 下限通配符
  • 四、示例
    • 4.1 示例一
    • 4.2 示例二

一、概述

Java 泛型即"类型参数化", 定义时只声明类型参数,然后在使用时传入具体的类型。就像定义函数时的形参和实参关系,定义函数时只是定义了形参,在运行时才传递的实参。

二、作用

2.1 语法糖

泛型在编译阶段有效, 其实本质是一种语法糖.

1. 编译期进行类型安全检查.

	// 没有使用泛型,  lis 中可以随意添加
   List list = new ArrayList();
	
   list.add("hello world");
   list.add(1);
   list.add(new Object());
   
   // 使用泛型, numbers 只能添加定义的类型, 否则在编译器报错
   List<Number> numbers = new ArrayList<>();
       
   numbers.add(new Integer(1));
   numbers.add(new Double(1.0));
    
   // numbers.add("hello world");   Required type:Number  Provided:String
   // numbers.add(new Object());    Required type:Number  Provided:Object

2. 替代强制类型转换, 实现自动和隐式转换.

	  // 不使用泛型
     List list = new ArrayList();
     list.add("hello world");
     Object o = list.get(0);          //直接获取时为 Object
     String s = (String) list.get(0); //强制类型转换

     // 使用泛型, 自动完成类型转换
     List<String> strList = new ArrayList<>();
     String str = strList.get(0);     //直接获取 String 类型

2.2 类型擦除

经过编译阶段, 所有的泛型信息都会被擦掉. 在生成的字节码中是不包含泛型中的类型信息的.

1. 运行时类对象不包含泛型信息

   ArrayList<String> list1 = new ArrayList<String>();
   list1.add("abc");

   ArrayList<Integer> list2 = new ArrayList<Integer>();
   list2.add(123);
   
   // 结果为 true, 运行时泛型类型 Integer  和 String 都被擦除掉了 , 只剩下原始类型.
   System.out.println(list1.getClass() == list2.getClass());

2. 反射调用, 可避开类型检查

   ArrayList<Integer> list = new ArrayList<Integer>();
   // 泛型类型为 Integer
   list.add(1); 
   // list.add("hello world");  编译时类型检查报错

   // 通过反射, 运行时成功添加字符串
   list.getClass().getMethod("add", Object.class).invoke(list, "hello world");

   System.out.println(list.get(0));    //输出 0
   System.out.println(list.get(1));    //输出 "hello world"

三、使用方法

泛型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

3.1 泛型定义

1. 泛型类和接口
类和接口的定义中,使用参数化类型定义,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。

	class 类名称 <泛型标识> {
           private 泛型标识  var; 
                        ....
	}

2. 泛型方法
方法定义中,使用参数化类型定义,被称为泛型方法。在调用方法的时候指明泛型的具体类型 。

	<泛型标识> 泛型标识 methodName(泛型标识或其他类型 参数…){}

3.2 泛型标识(通配符)

本质上字符都可以作为通配符,没啥区别,只不过是编码时的一种约定俗成的东西。比如 T ,我们可以换成 A-Z 之间的任何一个 字母都可以,并不会影响程序的正常运行,但是如果换成其他的字母代替 T ,在可读性上可能会弱一些。

3.2.1 约定通配符

  • ? 表示不确定的 java 类型
  • T (type)表示具体的一个java类型
  • K V (key value) 分别代表java键值中的Key Value
  • List item
  • E (element) 代表Element

3.2.2 上限通配符

用来限制类型的上限, 使用具体类型必须是限定类型或限定类型的子类

<? extends 限定类型>
<T extends 限定类型>

3.2.3 下限通配符

用来限制类型的下限, 使用具体类型必须是限定类型或限定类型的父类

<? super 限定类型>
<T super 限定类型> 

四、示例

4.1 示例一

	List<String> list = new ArrayList();
	list.add("1");
	list.add("2");
	// list.add(1); 类型检查
	...
	// 自动类型转换
	for(String s : list){  
		System.out.println(s);
	}

4.2 示例二

	// 定义一个泛型方法
    public static <T extends Comparable> T min(T a, T b) {
        if (a.compareTo(b) < 0) {
            return a;
        } else {
            return b;
        }
    }
	
	// 用于 Integer 
	int minInt = min(1, 2);
    System.out.println(minInt);

	// 用于 String
    String minStr = min("a", "b");
    System.out.println(minStr);

你可能感兴趣的:(JDK)