> 文档中心 > Java基础泛型

Java基础泛型

目录:

      • 前言
      • 一.泛型的理解和好处
        • 1.泛型的理解
          • (1) 使用传统方法的问题分析
          • (2) 使用泛型方式
        • 2.泛型的好处
      • 二.泛型介绍
        • 1.什么是泛型
        • 2.泛型的语法
        • 3.泛型使用细节
      • 三.自定义泛型
        • 1.自定义泛型类
        • 2.自定义泛型接口
        • 3.自定义泛型方法
      • 四.通配符
        • 1.泛型继承性
        • 2.通配符

前言

最近在回顾JavaSE部分的知识,对一些薄弱的知识进行记录,学习方式,通过视频和图书的进行学习,视频看B站韩顺平老师的30天学会Java,图书看Java核心技术 卷I 基础知识(原书第10版)。

韩顺平30天学会地址:Javahttps://www.bilibili.com/video/BV1fh411y7R8?spm_id_from=333.999.0.0
在这里插入图片描述
Java核心技术 卷I 基础知识(原书第10版)
在这里插入图片描述

一.泛型的理解和好处

1.泛型的理解

(1) 使用传统方法的问题分析

创建三个类Cat,People,Test类,具体代码如下:

package com.dudu;import java.util.ArrayList;import java.util.List;@SuppressWarnings({ "rawtypes", "unchecked" })public class Test {public static void main(String[] args) {List list =new ArrayList();list.add(new Cat(1, "嘟嘟"));list.add(new Cat(2, "小白"));list.add(new Cat(3, "小花猫"));list.add(new People(4, "铲屎官"));for(Object olist:list){// 向下转型if (olist instanceof Cat) {Cat cat = (Cat)olist;System.out.println(cat.toString());}else if (olist instanceof People) {People people =(People)olist;System.out.println(people.toString());}}}}class Cat{private int id;private String name;public Cat(int id, String name) {this.id = id;this.name = name;}@Overridepublic String toString() {return "Cat [id=" + id + ", name=" + name + "]";}}class People{private int id;private String name;public People(int id, String name) {this.id = id;this.name = name;}@Overridepublic String toString() {return "People [id=" + id + ", name=" + name + "]";}}

运行效果:
Java基础泛型
上面的代码能跑,但是存在一些问题:

  • 不能对加入集合ArrayList中的数据类型进行约束(不安全)

在遍历集合的时候,对于集合中的数据是通过判断实例类的方式执行不同向下转型,但是如果传入的是一个不确定的数据类型的时候,就无法获取该实例的属性方法,并且如果强制进行向下转型还会引发错误,这是不安全的。
在这里插入图片描述

  • 遍历的时候,需要进行类型转换,如果集合的数据较大,对效率有影响
    在这里插入图片描述
(2) 使用泛型方式
//泛型基本语法:类名 对象名 =new 类名/子类名(); // T为引用数据类型

使用泛型后,对集合中的数据进行限定后,不是该限定的数据类型,是无法加入到集合中去的,遍历的时候无需进行类型转换(编译的时候会自动识别该泛型的数据类型)。
在这里插入图片描述

2.泛型的好处

  • 编译时,检查添加元素的类型,提高了安全性
  • 减少了类型的转换次数,提高效率
  • 不再提示编译警告

二.泛型介绍

1.什么是泛型

传入的数据类型的数据类型,意思就是泛型是一种数据类型(引用数据类型),这个数据类型需要编译的时候传入相应的数据类型(引用数据类型),泛型可以限定类/接口(集合)的数据类型,可以在类/接口声明时通过一个标识 表示类/接口中某个属性的类型(接口不行) ,或者是 某个方法的返回值的类型,或者是 参数类型 ,是一种动态的数据类型。

代码:

package com.dudu;public class Test2 {public static void main(String[] args) {GenericparaDigmpor<String,Integer,Boolean> genericparaDigmpor= new GenericparaDigmpor<>("张三",18,true);System.out.println(genericparaDigmpor.toString());GenericparaDigmpor<Integer,String,String> genericparaDigmpor2 =new GenericparaDigmpor<>(18,"张三","李四");System.out.println(genericparaDigmpor2.toString());}}class GenericparaDigmpor<T,M,G>{// 属性的数据类型T t;M m;G g;// 方法的返回数据类型public M getM() {return m;}// 参数的数据类型public void name(G g) {System.out.println(g.getClass().getSimpleName());}public GenericparaDigmpor(T t,M m, G g){this.t = t;this.m = m;this.g = g;}public GenericparaDigmpor() {// TODO Auto-generated constructor stub}@Overridepublic String toString() {return "GenericparaDigmpor [t=" + t.getClass().getSimpleName() + ", m=" + m.getClass().getSimpleName() + ","+ " g=" + g.getClass().getSimpleName() + "]";}}

运行效果:
Java基础泛型

2.泛型的语法

  • 泛型的声明

interface 接口{}class 类{}

说明:
(1)其中,T.K,V不代表值,而是表示类型(泛型标识符)。
(2)任意字母都可以(一般为大写字母)。常用T表示,是Type的缩写。
(3)…表示泛型标识符可以有多个

  • 泛型的实例化
    类名 对象名 = new 类名/子类名();

List strList = new ArrayList();

3.泛型使用细节

  • 泛型的使用形式(JavaSE7及其以后版本,可以使用省略写法)
    类名 对象名 = new 类名/子类名();

泛型的使用方式其实有二种,另一种是在JavaSE7及其以后版本的一种省略写法
List strList = new ArrayList();

  • 有泛型限定的类中(如集合类),不加任何泛型修饰,默认使用数据类型为Object的泛型

List list =new ArrayList(); 相当于 List list =new ArrayList();

未使用泛型:
在这里插入图片描述
使用泛型:
在这里插入图片描述
注意:
List list = new ArrayList(); 不要写成 List list = new ArrayList(); 这种形式。

  • 泛型的数据类型是引用数据类型,对于一些基本数据类型,需要装箱为包装类

当泛型的数据类型为基本数据类型时,会报错!
Java基础泛型
在这里插入图片描述
虽然传入的是int但是实际上会装箱为Integer
在这里插入图片描述
上面的代码类似于:
Java基础泛型

  • 在指定泛型具体类型后,可以传入该数据或者其子类类型(多态)
import java.util.List;public class Test3 {public static void main(String[] args) {List<Animal> list =new ArrayList<>();// 传入该数据list.add(new Animal());// 传入该数据的子类对象list.add(new Cat_animal());// 传入该数据的子类对象的子类对象list.add(new DuDu());//list.add(new Alien());}}class Animal{public Animal() {// TODO Auto-generated constructor stubSystem.out.println(this.getClass().getSimpleName());}}class Cat_animal extends Animal{}class DuDu extends Cat_animal{}class Alien {}

运行效果:
Java基础泛型

三.自定义泛型

1.自定义泛型类

自定义泛型类就是自己定义的一个带泛型的类,在传统类名后面加上

语法:

class 类名<T,R...>{// 成员}

注意细节:

  • 普通成员(属性,方法)可以使用泛型(前面已经说了)
  • 使用泛型的数组,不能初始化
  • 静态方法中不能使用类的泛型
  • 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型) (前面已经说了)
  • 如果在创建对象时,没有指定类型默认为Object(前面已经说了)

使用泛型的数组,不能初始化:
在这里插入图片描述

静态方法,属性中不能使用类中的泛型标识符(静态在类加载的时候加载,执行在对象的前面,泛型是在创建对象的时候数据类型才确定,所以在静态中无法使用):
在这里插入图片描述
在这里插入图片描述

2.自定义泛型接口

自定义泛型接口就是自己定义的一个带泛型的接口,在传统接口名后面加上

语法:

interface 接口名<T,R...>{}

代码:

package com.dudu;public class Test5 {public static void main(String[] args) {TigerSum tigerSum = new TigerSumImple();tigerSum.method1("你好");tigerSum.method3(2.6);}}// 泛型接口interface Tiger_Two<T,M,G> {void method1(T t);M method2();G method3(G g);}interface TigerSum extends Tiger_Two<String, String, Double>{}class TigerSumImple implements TigerSum{@Overridepublic void method1(String t) {// TODO Auto-generated method stubSystem.out.println(t.getClass().getSimpleName());}@Overridepublic String method2() {// TODO Auto-generated method stubreturn null;}@Overridepublic Double method3(Double g) {// TODO Auto-generated method stubSystem.out.println(g.getClass().getSimpleName());return null;}}

运行效果:
Java基础泛型

注意细节:

  • 接口中,静态成员(属性)也不能使用泛型(这个和泛型类规定一样)
  • 泛型接口的类型,在继承接口或者实现接口时确定
  • 没有指定类型,默认为Object

接口中的属性为静态属性,不能使用泛型
Java基础泛型
泛型接口的类型,在实现接口时确定:
在这里插入图片描述
泛型接口的类型,在继承接口时确定:
在这里插入图片描述

泛型接口默认泛型类型为Object:
在这里插入图片描述

3.自定义泛型方法

语法:

修饰符 <T,R..> 返回类型 方法名(参数列表){}

注意: 一般泛型方法的参数列表都会有该泛型方法的泛型数据类型,不然泛型方法的数据类型采用的是默认数据类型Object。

代码:

package com.dudu;public class Test6 {public static void main(String[] args) {XiaoHu<String> xiaoHu =new XiaoHu<>();xiaoHu.method1();xiaoHu.method2("你好");xiaoHu.method2(new XiaoHu<String>());xiaoHu.method3("你好");xiaoHu.method3("Hello World!");}}// 泛型类中可以使用泛型方法class XiaoHu<G>{// 这是一个泛型方法,但是未使用该泛型参数(一般会使用)public <K> void method1() {System.out.println("这是一个泛型方法");}public <T> void method2(T t) {System.out.println("这是一个泛型方法,传入的泛型数据类型为:"+t.getClass().getSimpleName());}public void method3(G g) {System.out.println("这不是泛型方法,传入的泛型数据类型为:"+g.getClass().getSimpleName());}}// 接口中可以使用泛型方法interface XiaoHong{<T> void method1();<G> void method2(G g);}// 普通类中可以使用泛型方法class XiaoMing{public <G> void method1() {System.out.println("这是一个泛型方法");}public <T> void method2(T t) {System.out.println("这是一个泛型方法,传入的泛型数据类型为:"+t.getClass().getSimpleName());}}

运行效果:
Java基础泛型

注意细节:

  • 泛型方法,可以定义在普通类中,也可以定义在泛型类/接口中
  • 当泛型方法被调用时,类型会确定
  • 参数为泛型的方法不一定是泛型方法(方法的泛型标识符可能来自于类上的标识)

四.通配符

1.泛型继承性

泛型不具有继承性,但可以接受具有继承关系类的值

ArrayList后面的 要么不填(使用省略写法),要么就要填入和前面一致的数据类型!
在这里插入图片描述
泛型可以接受具有继承关系类的值(多态)
在这里插入图片描述

2.通配符

  • 支持任意泛型类型
  • :支持A类及其A类的子类,规定了泛型的上限(A类对象)
  • :支持A类及其A类的父类,不限于直接父类,规定了泛型的下限(A类对象)

在这里插入图片描述
代码:

package com.dudu;import java.util.ArrayList;import java.util.List;public class Test8 {public static void main(String[] args) {M m =new M();m.method1(new ArrayList<String>());m.method2(new ArrayList<A>());m.method2(new ArrayList<A_Son>());//m.method2(new ArrayList());m.method3(new ArrayList<A>());//m.method3(new ArrayList());m.method3(new ArrayList<A_Super>());}}class M{public void method1(List<?> list) {System.out.println("支持任意泛型类型");}public void method2(List<? extends A> list) {System.out.println("支持A类及其A类的子类");}public void method3(List<? super A> list) {System.out.println("支持A类及其A类的父类");}}class A_Super{public A_Super(){System.out.println(this.getClass().getSimpleName());}}class A extends A_Super{public A(){System.out.println(this.getClass().getSimpleName());}}class A_Son extends A{ public A_Son(){ System.out.println(this.getClass().getSimpleName()); }}

运行效果:
Java基础泛型

如果要传入一个带泛型的集合对象的时候 List 无法直接作为参数的数据类型
在这里插入图片描述
此时就可以使用 List :
Java基础泛型

如果传入的集合的泛型为一个自定义类对象的数据类型, List 就不行了,需要使用 ,并且这二种方式也是对泛型进行了一种限定(在本类和子类之间,在本类和父类之间)。
在这里插入图片描述

:支持A类及其A类的子类; :支持A类及其A类的父类:

在这里插入图片描述