java泛型的基本介绍和使用

     2022-03-26     437

关键词:

现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用。泛型在java中,是一个十分重要的特性,所以要好好的研究下。

一、泛型的基本概念

 泛型的定义:泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。

  泛型思想早在C++语言的模板(Templates)中就开始生根发芽,在Java语言处于还没有出现泛型的版本时,只能通过Object是所有类型的父类和类型强制转换两个特点的配合来实现类型泛化。例如在哈希表的存取中,JDK 1.5之前使用HashMap的get()方法,返回值就是一个Object对象,由于Java语言里面所有的类型都继承于java.lang.Object,那Object转型为任何对象成都是有可能的。但是也因为有无限的可能性,就只有程序员和运行期的虚拟机才知道这个Object到底是个什么类型的对象。在编译期间,编译器无法检查这个Object的强制转型是否成功,如果仅仅依赖程序员去保障这项操作的正确性,许多ClassCastException的风险就会被转嫁到程序运行期之中。

  泛型技术在C#和Java之中的使用方式看似相同,但实现上却有着根本性的分歧,C#里面泛型无论在程序源码中、编译后的IL中(Intermediate Language,中间语言,这时候泛型是一个占位符)或是运行期的CLR中都是切实存在的,List<int>与List<String>就是两个不同的类型,它们在系统运行期生成,有自己的虚方法表和类型数据,这种实现称为类型膨胀,基于这种方法实现的泛型被称为真实泛型。

  Java语言中的泛型则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经被替换为原来的原始类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此对于运行期的Java语言来说,ArrayList<int>与ArrayList<String>就是同一个类。所以说泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。(类型擦除在后面在学习)

  使用泛型机制编写的程序代码要比那些杂乱的使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。泛型对于集合类来说尤其有用。

  泛型程序设计(Generic Programming)意味着编写的代码可以被很多不同类型的对象所重用。


实例分析:

  在JDK1.5之前,Java泛型程序设计是用继承来实现的。因为Object类是所用类的基类,所以只需要维持一个Object类型的引用即可。就比如ArrayList只维护一个Object引用的数组:


[java] view plain copy

  1. public class ArrayList//JDK1.5之前的  

  2. {  

  3.     public Object get(int i){......}  

  4.     public void add(Object o){......}  

  5.     ......  

  6.     private Object[] elementData;  

  7. }  

这样会有两个问题:

1、没有错误检查,可以向数组列表中添加类的对象

2、在取元素的时候,需要进行强制类型转换

这样,很容易发生错误,比如:


[java] view plain copy

  1. /**jdk1.5之前的写法,容易出问题*/  

  2. ArrayList arrayList1=new ArrayList();  

  3. arrayList1.add(1);  

  4. arrayList1.add(1L);  

  5. arrayList1.add("asa");  

  6. int i=(Integer) arrayList1.get(1);//因为不知道取出来的值的类型,类型转换的时候容易出错  

这里的第一个元素是一个长整型,而你以为是整形,所以在强转的时候发生了错误。

所以。在JDK1.5之后,加入了泛型来解决类似的问题。例如在ArrayList中使用泛型:

[java] view plain copy

  1.                 /** jdk1.5之后加入泛型*/  

  2.         ArrayList<String> arrayList2=new ArrayList<String>();  //限定数组列表中的类型  

  3. //      arrayList2.add(1); //因为限定了类型,所以不能添加整形  

  4. //      arrayList2.add(1L);//因为限定了类型,所以不能添加整长形  

  5.         arrayList2.add("asa");//只能添加字符串  

  6.         String str=arrayList2.get(0);//因为知道取出来的值的类型,所以不需要进行强制类型转换  


还要明白的是,泛型特性是向前兼容的。尽管 JDK 5.0 的标准类库中的许多类,比如集合框架,都已经泛型化了,但是使用集合类(比如 HashMap 和 ArrayList)的现有代码可以继续不加修改地在 JDK 1.5 中工作。当然,没有利用泛型的现有代码将不会赢得泛型的类型安全的好处。


在学习泛型之前,简单介绍下泛型的一些基本术语,以ArrayList<E>ArrayList<Integer>做简要介绍:

整个成为ArrayList<E>泛型类型

ArrayList<E>中的 E称为类型变量或者类型参数

整个ArrayList<Integer> 称为参数化的类型

ArrayList<Integer>中的integer称为类型参数的实例或者实际类型参数

·ArrayList<Integer>中的<Integer>念为typeof   Integer

ArrayList称为原始类型


二、泛型的使用

泛型的参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。下面看看具体是如何定义的。

1、泛型类的定义和使用


一个泛型类(generic class)就是具有一个或多个类型变量的类。定义一个泛型类十分简单,只需要在类名后面加上<>,再在里面加上类型参数:

[java] view plain copy

  1. class Pair<T> {  

  2.     private T value;  

  3.         public Pair(T value) {  

  4.                 this.value=value;  

  5.         }  

  6.         public T getValue() {  

  7.         return value;  

  8.     }  

  9.     public void setValue(T value) {  

  10.         this.value = value;  

  11.     }  

  12. }  

现在我们就可以使用这个泛型类了:

[java] view plain copy

  1. public static void main(String[] args) throws ClassNotFoundException {  

  2.         Pair<String> pair=new Pair<String>("Hello");  

  3.         String str=pair.getValue();  

  4.         System.out.println(str);  

  5.         pair.setValue("World");  

  6.         str=pair.getValue();  

  7.         System.out.println(str);  

  8.     }  


Pair类引入了一个类型变量T,用尖括号<>括起来,并放在类名的后面。泛型类可以有多个类型变量。例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:

public class Pair<T,U>{......}

注意:类型变量使用大写形式,且比较短,这是很常见的。在Java库中,使用变量E表示集合的元素类型,K和V分别表示关键字与值的类型。(需要时还可以用临近的字母U和S)表示“任意类型”。


2、泛型接口的定义和使用

定义泛型接口和泛型类差不多,看下面简单的例子:


[java] view plain copy

  1. interface Show<T,U>{  

  2.     void show(T t,U u);  

  3. }  

  4.   

  5. class ShowTest implements Show<String,Date>{  

  6.     @Override  

  7.     public void show(String str,Date date) {  

  8.         System.out.println(str);  

  9.         System.out.println(date);  

  10.     }  

  11. }  

测试一下:



[java] view plain copy

  1. public static void main(String[] args) throws ClassNotFoundException {  

  2.         ShowTest showTest=new ShowTest();  

  3.         showTest.show("Hello",new Date());  

  4.     }  


3、泛型方法的定义和使用


泛型类在多个方法签名间实施类型约束。在 List<V> 中,类型参数 V 出现在 get()、add()、contains() 等方法的签名中。当创建一个 Map<K, V> 类型的变量时,您就在方法之间宣称一个类型约束。您传递给 add() 的值将与 get() 返回的值的类型相同。

类似地,之所以声明泛型方法,一般是因为您想要在该方法的多个参数之间宣称一个类型约束。

举个简单的例子:


[java] view plain copy

  1. public static void main(String[] args) throws ClassNotFoundException {  

  2.         String str=get("Hello""World");  

  3.         System.out.println(str);  

  4.     }  

  5.   

  6.     public static <T, U> T get(T t, U u) {  

  7.         if (u != null)  

  8.             return t;  

  9.         else  

  10.             return null;  

  11.     }  




三、泛型变量的类型限定


在上面,我们简单的学习了泛型类、泛型接口和泛型方法。我们都是直接使用<T>这样的形式来完成泛型类型的声明。

有的时候,类、接口或方法需要对类型变量加以约束。看下面的例子:

有这样一个简单的泛型方法:


[java] view plain copy

  1. public static <T> T get(T t1,T t2) {  

  2.         if(t1.compareTo(t2)>=0);//编译错误  

  3.         return t1;  

  4.     }  

因为,在编译之前,也就是我们还在定义这个泛型方法的时候,我们并不知道这个泛型类型T,到底是什么类型,所以,只能默认T为原始类型Object。所以它只能调用来自于Object的那几个方法,而不能调用compareTo方法。


可我的本意就是要比较t1和t2,怎么办呢?这个时候,就要使用类型限定,对类型变量T设置限定(bound)来做到这一点。

我们知道,所有实现Comparable接口的方法,都会有compareTo方法。所以,可以对<T>做如下限定:


[java] view plain copy

  1. public static <T extends Comparable> T get(T t1,T t2) { //添加类型限定  

  2.         if(t1.compareTo(t2)>=0);  

  3.         return t1;  

  4.     }  


类型限定在泛型类、泛型接口和泛型方法中都可以使用,不过要注意下面几点:



1、不管该限定是类还是接口,统一都使用关键字 extends

2、可以使用&符号给出多个限定,比如

[java] view plain copy

  1. public static <T extends Comparable&Serializable> T get(T t1,T t2)  

3、如果限定既有接口也有类,那么类必须只有一个,并且放在首位置


[java] view plain copy

  1. public static <T extends Object&Comparable&Serializable> T get(T t1,T t2)  


《javase基础知识》泛型的基本介绍和应用。

目录一、泛型的基本介绍1、传统方法存在的问题2、泛型的基本介绍3、泛型的语法4、泛型的好处二、自定义泛型1、注意事项2、自定义泛型方法 三、自定义泛型接口 四、泛型的继承和通配符 五、JUnit 一、泛型的基本介绍1、... 查看详情

java中泛型的深入理解(代码片段)

文章目录泛型深入泛型基本介绍自定义泛型类自定义泛型方法自定义泛型接口泛型通配符和上下限泛型深入泛型基本介绍泛型的概述:泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。泛... 查看详情

泛型1:介绍及基本使用方式(代码片段)

前言泛型实现了参数化类型的概念;泛型的主要目的之一是用来指定容器要持有什么类型的对象,编译器保证类型的正确性;多态也是一种泛化机制;基本类型无法作为类型参数;一.基本使用方式  泛型基本分为泛型类型和泛型... 查看详情

java学习----泛型

目录  1.泛型的定义  2.泛型的使用  3.泛型通配符 一、泛型的定义  泛型是java5的新特性,使用泛型会让程序编写简单安全,在编译的时候就会检查类型是否安全  定义:所谓泛型就是允许在定义类、接口和方... 查看详情

java泛型的作用及其基本概念

一、泛型的基本概念   java与c#一样,都存在泛型的概念,及类型的参数化。java中的泛型是在jdk5.0后出现的,但是java中的泛型与C#中的泛型是有本质区别的,首先从集合类型上来说,java中的ArrayList<Integer>和ArrayList&... 查看详情

《徐徐道来话java》:泛型的基本概念

泛型是一种编程范式(ProgrammingParadigm),是为了效率和重用性产生的。由AlexanderStepanov(C++标准库主要设计师)和DavidMusser(伦斯勒理工学院CS名誉教授)首次提出,自实现始,就成为了ANSI/ISOC++重要标准之一。Java自1.5版本开始... 查看详情

详解java泛型(代码片段)

目录1为什么使用泛型2泛型的语法3.泛型的编译步骤3.1擦除机制3.2不可以实例化泛型类型数组4.了解裸类型5.泛型的上界6.泛型方法7.通配符(?)7.1理解通配符7.2通配符上界7.3通配符下界 8.包装类8.1基本数据类型对应包装类... 查看详情

java泛型的实现原理

 1.基本学过JAVA的人都知道一点泛型,明白常出现的位置和大概怎么使用。  在类上为:class类名<T>{}  在方法上为:public<T>void方法名(Tx){}  就不再赘述了。  2.泛型就是将类型变成了参数去传入,使得可以... 查看详情

java泛型--泛型的简单介绍以及常用情况(代码片段)

一.泛型的基本概念泛型是JavaSE5引入的一个新概念,实现了参数化类型的概念,并且使代码可以应用于多种类型。在日常编写程序时,我们都会很注重“泛化”,像多态其实就是一种类型的泛化,将子类的对象... 查看详情

java重点--泛型(代码片段)

文章目录💖泛型的概念✨使用泛型的好处与弊端✨定义和使用含有泛型的类✨定义和使用含有泛型的方法✨定义和使用含有泛型的接口✨泛型的通配符✨通配符的高级使用--受限泛型✨斗地主小案例💖泛型的概念泛型是... 查看详情

什么是泛型?泛型的基本原理与使用优势。(代码片段)

目录 1.什么是泛型?2.先来看一个简单的泛型例子3.那么T是什么呢?4.如何使用泛型,并将类型作为参数传入呢?5.泛型的基本原理6.使用泛型的好处1.什么是泛型?泛型将接口的概念进一步延伸,“泛型”... 查看详情

java泛型简介定义和使用含有泛型的类定义和使用含有泛型的方法定义和使用含有泛型的接口泛型通配符?受限泛型(代码片段)

泛型简介:集合中存储数据的类型称之为泛型,泛型是一种未知的数据类型,当不知道使用什么数据类型的时候可以使用泛型;当创建对象时在指明数据类型并赋值给泛型即可;泛型也可以看做是一个变量ÿ... 查看详情

java讲课笔记35:初探泛型

文章目录零、本讲学习目标一、泛型的概念二、泛型的好处(一)提高程序类型安全(二)消除强制类型转换三、案例演示泛型使用(一)类使用泛型(二)构造方法使用泛型(三)设置多个泛型(四)使用通配符(五)使用泛... 查看详情

java8基础知识泛型的约束与局限性

泛型的约束与局限性由于泛型是通过类型擦除、强制类型转换和桥方法来实现的,所以存在某些局限(大多来自于擦除)。不能使用基本类型实例化类型参数类型参数都是类,要用包装器将基本类型包装才可以作为类型参数(原... 查看详情

java泛型用法

本质:参数化类型泛型的擦除:​泛型只在编译阶段有效,编译之后JVM会采取去泛型化的措施.​泛型在运行阶段是没有效果泛型通配符的介绍概念泛型的类型擦除泛型只在编译阶段有效,泛型类型在逻辑上可看成是多个不同的类... 查看详情

java泛型用法

本质:参数化类型泛型的擦除:​泛型只在编译阶段有效,编译之后JVM会采取去泛型化的措施.​泛型在运行阶段是没有效果泛型通配符的介绍概念泛型的类型擦除泛型只在编译阶段有效,泛型类型在逻辑上可看成是多个不同的类... 查看详情

java基础:泛型的具体介绍与使用(代码片段)

...得我的文章不错,记得一键三连,感谢~文章目录泛型一、为什么要有泛型(Generic)1、泛型:标签2、举例:3、泛型的设计背景:4、泛型的概念5、那么为什么要有泛型呢,直接Object不是也可以存储数据吗࿱... 查看详情

java中的泛型

...很多时候我们并不关心这个类的类型而是这个类的能力。泛型的出现让我们的代码和代码所能操作的类型不在绑定在一起,不仅可以复用代码降低耦合还可以提高代码的可读性和安全性。  首先,我们现在看一段代码来介... 查看详情