Java 理解泛型的基本含义

Posted Firm陈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 理解泛型的基本含义相关的知识,希望对你有一定的参考价值。

一.Java 泛型
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

二.泛型方法
你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

下面是定义泛型方法的规则:

所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的)。
每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。

public class ElementDemo {
    
    public static void main(String[] args) {
        
        //<Integer>运行时类型
        //使用泛型后,如果实例化是定义的类型与对象传入的类型不一致,就会在编译时期报错。
        Test<Integer> t1 = new Test<>();
        t1.add(666); 
        
        Test<String> t2 = new Test<>();
        t2.add("cjj");
    }
}

/**
 * "E" 在这里并没有实际意义,你也可以用别的字母代替
 * 它的作用就是在实例化Test类的时候,传入什么类型它就调用什么类型
 */
class Test<E>{
    public void add(E e) {
        
        System.out.println(e);
    }
}

注意:
泛型的命名只要符合标识符的命名规则即可
习惯上泛型一般只使用一个大写字母进行命名
(1)E - Element (在集合中使用,因为集合中存放的是元素)
(2)T - Type(Java 类)
(3) K - Key(键)
(4)V - Value(值)
(5) N -Number(数值类型)
(6)? - 表示不确定的java类型
S、U、V - 2nd、3rd、4th types

遇到,,<K,V>等,是用到了java中的泛型。

一般使用来声明类型持有者名称,自定义泛型类时,类持有者名称可以使用T(Type)
如果是容器的元素可以使用E(Element),若键值匹配可以用K(Key)和V(Value)等, 若是<?>,则是默认是允许Object及其下的子类,也就是java的所有对象了。 所以说,如果是字每A,B,C,D…定义的,就是泛型,这里T只是名字上的意义而已T—type,E----Element K----key, V----value 如果是?定义的,就是普通的Object或者其子类
举例说明:
Set 表示 集合里 是 T类的实例
List 表示 集合里 是 E类的实例
List<?> 表示 集合里的对象类型不确定,未指定
List 同 List<?> 是一样的。

三.泛型的作用
1.用泛型:

List<T> list=new ArrayList<T>();  
T t=list.

2.不用泛型

List  list=new ArrayList();  
T t=(T)list.get(0);

相信你已经看出:
a.用泛型时,是确定了集合内的元素的类型,在编译时确定了元素的类型,再取出来时已经不再需要强转, 增强程序可读性,稳定性和效率
b.不用泛型时,如果是装入集合操作,那么元素都被当做Object对待,失去自己的类型,那么从集合中取出来时, 往往需要转型,效率低,容易产生错误 。

四.泛型向下兼容

<? extends 类/接口>
import java.util.ArrayList;
import java.util.List;

public class ElementDemo {
    public static void main(String[] args) {
        
        //实例化一个Integer类型的数组列表对象,里面存储的数据都是int型数据
        List<Integer> in = new ArrayList<>();
        in.add(1);
        in.add(2);
        in.add(3);
        in.add(4);
        in.add(5);
        in.add(6);
        //实例化一个Double类型的数组列表对象,里面存储的数据都是Double类型的
        List<Double> dos = new ArrayList<>();
        dos.add(3.6);
        dos.add(4.2);
        dos.add(6.8);
        dos.add(7.7);
        dos.add(0.2);
        
        //调用方法
        print(in);
        print(dos);
    }
    
    // 写一个新的方法来遍历元素类型是数字的列表
    // 元素类型是Number或者是其子类
    // ? extends 类/接口 表示传入这个类/接口或者是其子类/子接口对象
    // 所能传入的元素的最大类型限定为Number
    // 规定了泛型的上限
    public static void print(List<? extends Number> list) {
        
        //在方法体里面不能再往对象里添加元素,null除外
        list.add(null);
        
        //打印对象里面的元素
        System.out.println(list);
    }
}

向下造型规定了泛型的上限,上限的子类都可以向泛型方法传入对象。

五.泛型向上兼容

<? super 类/接口>
import java.util.ArrayList;
import java.util.List;

public class ElementDemo1 {
    public static void main(String[] args) {
        
        List<String> str = new ArrayList<>();
        str.add(0, "cjj");
        
        print(str);
    }
    
    // 泛型的下限
    // 传入元素类型是String及其父类的列表
    // ? super 类/接口 表示传入这个类/接口及其父类/父接口的对象
    // 表示传入的最小类型是String    
    public static void print(List<? super String> list) {
        
        //方法体里面可以添加元素
        list.add("add");
        
        for(Object o : list){
            System.out.println(o);
        }
    }
}

向上造型规定了泛型的下限,下限的父类都可以向泛型方法传入对象。

注:List<? extends T>和List <? super T>有什么区别?
List<? extends T>可以接受任何继承自T的类型的List,
List<? super T>可以接受任何T的父类构成的List。
例如List<? extends Number>可以接受List或List。

以上是关于Java 理解泛型的基本含义的主要内容,如果未能解决你的问题,请参考以下文章

Java中的泛型 (上) - 基本概念和原理

Java泛型深入理解

java中的泛型的使用与理解

对java泛型的理解

JAVA泛型的基本使用

Java反射的理解-- 通过反射了解集合泛型的本质