• Java - 泛型


    前言

              学习 Java 泛型 内容!

    一、为什么

    Java 泛型是 JDK 5 中引入的一个新特性,目的是用来弥补集合可以容纳各种类型数据导致的类型异常。
    集合中可以存放字符串、整型数据等各种数据,对于集合而言,都将其统一当作是 object 类型(Java 中所有类的父类是 Object)。类比,集合是一个大房子,各种数据类比为人、狗、猫等具体的,对于房子而言都将其统一看作是活物。
    存在问题:将所有类型数据都当作 object 类型存放,后续使用具体数据类型时需要强制类型转换,造成类型转换错误。

    List list = new ArrayList ();
    list.add("hello");
    list.add(6);
    
    for (object o : list) {
    	System.out.println((String) o);  // 发生错误:Integer 不能转换成 String 类型
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    二、泛型

    泛型是什么?

    定义泛型时可以类比成增加了一个安检功能,使用时如果使用泛型(安检功能),则会对不符合限制(特定数据类型)的进行过滤,也可以不适用泛型(安检功能),不使用就没有过滤功能(默认就是 Object 类型)。
    所谓的泛型就是参数化类型,即将要操作的类型作为一个参数。
    参数化类型是什么?字面拆解。参数化变成参数类型数据类型,例如,StringInterger参数化类型将类型当作参数。例如,将 String 直接变成参数。

    public class Main {
    	public static void main(String[] args) {
    		List list = new ArrayList();  // 不使用泛型
    		// <String>  泛型表达:将 String 类型变成集合 List 的参数
    		List<String> list1 = new ArrayList<>();  
    	}
    	// 该方法规定需要传入一个 String 类型的参数(具体的字符串)
    	public void Do(String s) {
    		System.out.println(s);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    泛型的作用:给集合加上特定的限制,只能存储特定的类型数据。

    类型参数

    对于方法,方法参数有形参和实参。对于泛型,参数化类型,就是将类型当作参数,类型参数就是 <> 内的东西。类型参数也分为类型实参和类型形参。

    1. 类型实参

      List<String> list1 = new ArrayList<>();
      
      • 1

      <> 内的 String 就是类型实参,即实际的类型参数,这里的类型参数就是各个数据类型。

    2. 类型形参

      public interface List<E> extends Collection<E> {
      	...
      }
      
      • 1
      • 2
      • 3

      对于泛型就是使用一些大写的英文字母来作为类型形参,这列的 E 就是类型形参,代表通用型。例如,E:在集合框架中使用,K V:含有映射关系使用(Map),N:用于数字,T S U V:通用类型。

    泛型使用

    对于泛型,如果是使用泛型用类型实参,如果是定义泛型接口或泛型类用类型形参。

    1. 定义泛型接口

    interface MyList<E> {  // E 作为类型形参
    	// 打印泛型实际类型实参的类型名称
    	void showTypeName(E e)
    }
    
    • 1
    • 2
    • 3
    • 4
    // 通过 MyListImp 类实现一个泛型接口
    public class MyListImp<E> implents MyList<E>{
    	public void showTypeName(E e) {
    		System.out.println(e.getClass().getName());
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    // 测试类
    public class Main {
    	public static void main(String[] args) {
    		MyList<String> myList = new MyListImp<>();
    		myList.showTypeName("hello");
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2. 定义泛型类

    // 定义
    // 给类增加泛型,相当于给类增加了过滤
    public class FxClass<G> {  // G 类型形参,定义时不能确定具体的类型,后面使用时传入类型实参确定 G 类型
    	private G g;
    	public G getG() {
    		return g;
    	}
    	public void setG(G g) {
    		this.g = g;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    // 使用泛型类:使用时会根据泛型定义对操作进行可一些过滤
    public class Main {
    	public static void main(String[] args) {
    		FxClass<String> fxClass = new FxClass<>();
    		fxClass.setG("自定义泛型类");
    		System.out.println(fxClass.getG());
    		Test test = new Test();
    	}
    
    // 泛型类的继承
    class Test extends FxClass<String> {  // 继承泛型类的时候要指定具体的类型实参
    	
    }
    
    // 原始类型
    class Test extends FxClass {  // 不写类型实参被称为原始类型等价于 class Test extends FxClass<object>
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    泛型类是不存在的,泛型类并不是一个新的种类

    List list = new ArrayList();  // 没有使用泛型
    List<String> stringlist = new ArrayList<>();  // 使用了泛型:没有生成新的 List 本质上还是上一个 List,只不过泛型做了规定只能装载特定的数据
    
    • 1
    • 2

    使用通配符

    public void doS(List<?> list) {
    }
    
    • 1
    • 2

    3. 泛型方法

    修饰符 <T,E, … 形参> 返回值类型 方法名称 (形参列表) {
                  方法体,具体的逻辑实现
    }

    public class Test {
    	public static void main(String[] args) {
    	// 普通方法
    	public void doS(String s) {
    		System.out.println(s.getClass().getName());
    	}
    
    	// 泛型方法
    	public <T> void doSS(T t) {  // <T> T 形参
    		System.out.println(T.getClass().getName());
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    泛型擦除

  • 相关阅读:
    Nacos单机启动的两种方式
    (哈希表 ) 202. 快乐数——【Leetcode每日一题】
    Kafka生产者
    树的前中后序深度优先算法(迭代法+递归法)-日记篇
    C++PrimerPlus 第七章 函数-C++的编程模块-7.3 函数和数组
    Android流媒体开发之路三:基于NDK开发Android平台RTSP播放器
    html中使用JQ自定义锚点偏移量
    力扣leetcode 1608. 特殊数组的特征值
    ES 8.x 向量检索性能测试 & 把向量检索性能提升100倍!
    uniapp 地图跳转到第三方导航软件 直接打包成apk
  • 原文地址:https://blog.csdn.net/weixin_39903708/article/details/125616316