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

Ever69 Ever69     2022-12-14     615

关键词:

目录

 

1. 什么是泛型?

2. 先来看一个简单的泛型例子

3. 那么T是什么呢?

4. 如何使用泛型,并将类型作为参数传入呢?

5. 泛型的基本原理

6. 使用泛型的好处


1. 什么是泛型?

泛型将接口的概念进一步延伸,“泛型”的字面意思就是广泛的类型。类、接口和方法代码可以应用于非常广泛的类型,代码与它们能够操作的数据类型不再绑定在一起,同一套代码可以用于多种数据类型,这样不仅可以复用代码,降低耦合性,而且还提高了代码的可读性以及安全性。讲起来优点抽象,我们看个实际的例子。

2. 先来看一个简单的泛型例子

package genericity.demo;

/**
 * @author BastetCat
 * @data 2019/8/8 21:14
 */

public class Pair<T> 
    T one;
    T two;

    public Pair(T one, T two) 
        this.one = one;
        this.two = two;
    

    public T getOne() 
        return one;
    

    public T getTwo() 
        return two;
    

观察和普通类的区别:

  1. 类名后面多了一个<T>
  2. one 和 two的类型都是T

3. 那么T是什么呢?

T 表示类型参数

泛型就是类型参数化,处理的数据类型不是固定的,而是可以作为参数传入。

现在我们知道了,泛型把类型作为了参数来使用。

4. 如何使用泛型,并将类型作为参数传入呢?

如下代码:我们分别new了三Pair对象,其中传入了不同类型的类型参数(Integer、Character、String)。

package genericity.demo;

/**
 * @author BastetCat
 * @data 2019/8/8 21:22
 */

public class Test 
    public static void main(String[] args) 
        
        Pair<Integer> pairInteger =  new Pair<Integer>(1,2);
        int one1 = pairInteger.getOne();
        int two1 = pairInteger.getTwo();
        System.out.println("one:"+one1+",two:"+two1);

        Pair<Character> pairCharacter  =  new Pair<Character>('一','二');
        char one2 = pairCharacter.getOne();
        char two2 = pairCharacter.getTwo();
        System.out.println("one:"+one2+",two:"+two2);

        Pair<String> pairString  =  new Pair<String>("I","II");
        String one3 = pairString.getOne();
        String two3 = pairString.getTwo();
        System.out.println("one:"+one3+",two:"+two3);
    

结果如下:

one:1,two:2
one:一,two:二
one:I,two:II

当然我们不仅可以传入一个类型参数,也可以传入多个类型参数。多个类型参数之间用 逗号“,”隔开。如下面的例子:

package genericity.demo;

/**
 * @author BastetCat
 * @data 2019/8/8 21:37
 */

public class PairTwo <U,V> 
    U one;
    V two;

    public PairTwo(U one, V two) 
        this.one = one;
        this.two = two;
    

    public U getOne() 
        return one;
    

    public V getTwo() 
        return two;
    

可以这么使用:

PairTwo<String,Integer> pairTwo = new PairTwo<>("牛牛",20);

注意:自 Java 7 开始,支持省略后面的类型参数,让书写更简单些。

5. 泛型的基本原理

泛型类型参数到底是什么?为什么一定要定义类型参数呢?定义普通类,直接使用Object也是可以呀。如之前的Pair类我们可以写成:

package genericity.demo;

/**
 * @author BastetCat
 * @data 2019/8/8 21:44
 */

public class PairObject 
    Object one;
    Object two;

    public PairObject(Object one, Object two) 
        this.one = one;
        this.two = two;
    

    public Object getOne() 
        return one;
    

    public Object getTwo() 
        return two;
    

然后这样使用,也是同样的效果:

package genericity.demo;

/**
 * @author BastetCat
 * @data 2019/8/8 21:46
 */

public class TestPairObject 
    public static void main(String[] args) 
        PairObject pairObject1 = new PairObject(1,2);
        int one1 =(int)pairObject1.getOne();
        int two1 =(int)pairObject1.getTwo();
        System.out.println("one:"+one1+",two:"+two1);

        PairObject pairObject2 = new PairObject("yi","er");
        String one2 =(String)pairObject2.getOne();
        String two2 =(String)pairObject2.getTwo();
        System.out.println("one:"+one2+",two:"+two2);
    

输出结果:

one:1,two:2
one:yi,two:er

我们可以看到,确确实实我们的使用Object + 强制类型转换也实现了相同的结果。事实上,我们Java泛型的内部原理就是这样的。

我们使用JAD工具来反编译我们的Pair.class 与 Test.class得到的结果如下:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   Pair.java

package genericity.demo;
public class Pair

    public Pair(Object obj, Object obj1)
    
        one = obj;
        two = obj1;
    
    public Object getOne()
    
        return one;
    
    public Object getTwo()
    
        return two;
    
    Object one;
    Object two;





// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   Test.java

package genericity.demo;
import java.io.PrintStream;
// Referenced classes of package genericity.demo:
//            Pair

public class Test

    public Test()
    
    
    public static void main(String args[])
    
        Pair pair = new Pair(Integer.valueOf(1), Integer.valueOf(2));
        int i = ((Integer)pair.getOne()).intValue();
        int j = ((Integer)pair.getTwo()).intValue();
        System.out.println((new StringBuilder()).append("one:").append(i).append(",two:").append(j).toString());
        Pair pair1 = new Pair(Character.valueOf('\\u4E00'), Character.valueOf('\\u4E8C'));
        char c = ((Character)pair1.getOne()).charValue();
        char c1 = ((Character)pair1.getTwo()).charValue();
        System.out.println((new StringBuilder()).append("one:").append(c).append(",two:").append(c1).toString());
        Pair pair2 = new Pair("I", "II");
        String s = (String)pair2.getOne();
        String s1 = (String)pair2.getTwo();
        System.out.println((new StringBuilder()).append("one:").append(s).append(",two:").append(s1).toString());
    

通过以上的分析:

我们可以得知,Java的编译器将java源文件编译成字节码.class文件,虚拟机加载并运行。对于泛型类,java编译器会将其转换为普通的非泛型代码。将类型T擦除,然后替换为Object,插入必要的强制类型转换。Java虚拟机实际执行的时候,并不知道泛型这回事,只知道普通的类及代码。

那么为什么泛型要这样设计呢?

因为泛型是 Java 5 以后才支持的,这么设计是为了兼容性,而不得已的一个选择。

6. 使用泛型的好处

  • 代码复用:我们一套代码可以支持不同的类性。
  • 降低了耦合性:代码逻辑和数据类型之间分离,实现了解耦。
  • 更好的可读性:我们在使用集合的时候,定义了一个list 如List<String>,一看便知道这个一个存放String类型的list。
  • 更高的安全性:语言和程序设计的一个重要目标就是将bug消灭在摇篮里,能在写的时候消灭,就不要留在运行的时候。如我们定义一个List<String>这样的一个list。当我们往list里面放其他非String类型的数据时,我们的IDE(如Eclipse)就会报错提示。就算没有IDE。编译时,Java编译器也会提示,这称之为类型安全。这样就为程序设置了一道安全防护。同样的,使用泛型还可以省去使用普通对象时繁琐的强制类型转换。相反,使用普通对象,编译时并不会提示。假如传入的参数类型和最后强制类型转换的类型不一致。运行时就会出现ClassCastException,使用泛型则不会。

java数据结构list的基本用法(代码片段)

文章目录一、简单认识泛型1.什么是泛型2.泛型的意义3.泛型是如何编译的4.泛型总结二、包装类1.什么是包装类2.基本数据类型与对应的包装类型3.装箱和拆箱4.关于拆箱和装箱常见面试题三、List的使用1.ArrayList简单介绍2.ArrayList使... 查看详情

java泛型定义和基本使用笔记(代码片段)

...面向对象编程及各种设计模式中有非常广泛的应用。 为什么这么说呢,首先我们要理解什么是泛型,为什么要使用泛型? Java泛型是J2SE1.5中引入的一个新特性,其本质是参数化类型,也就是说所操作的数据类... 查看详情

typescript泛型(代码片段)

TypeScript泛型1什么是泛型2泛型方法3泛型类4泛型接口1什么是泛型泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、... 查看详情

为啥 NIO.2 FileVisitor 类型是泛型的?

...型是泛型的?【英文标题】:WhyisNIO.2FileVisitortypegeneric?为什么NIO.2FileVisitor类型是泛型的?【发布时间】:2013-04-3015:57:05【问题描述】:我正在研究JavaNIO.2及其文件操作,目前我正在使用文件树遍历函数和类。NIO.2FileVisitorAPI很棒... 查看详情

深入java泛型(三泛型的上下边界)(代码片段)

...;:是指“下界通配符(LowerBoundsWildcards)”为什么要用通配符和边界?使用泛型的过程中,经常出现一种很别扭的i情况。比如我们有Fruit类和它的派生 查看详情

javase集合框架——泛型(代码片段)

目录一、为什么要有泛型二、在集合中使用泛型2.1集合使用泛型2.2Comparable类和Comparator比较器使用泛型 1)Comprable类使用泛型2)Comparator使用泛型三、自定义泛型(泛型类、泛型接口;泛型方法)3.1泛型类/泛型... 查看详情

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

...概念泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型,泛型也可以看做是一个变量,用来接收数据类型。Ee 查看详情

大数据必学java基础(五十五):泛型深入了解(代码片段)

文章目录泛型深入了解一、引入1、什么是泛型(Generic)2、没有泛型的时候使用集合3、JDK1.5以后开始使用泛型,集合中使用泛型4、泛型总结二、自定义泛型结构1、泛型类,泛型接口2、泛型方法3、泛型参数存在... 查看详情

详解java泛型(代码片段)

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

什么是泛型

Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter)。声明的类型参数在使用时用具体的类型来替换。 泛型的本质是参数化类型,也就是说所操作的数据类型被指定... 查看详情

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

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

深入java泛型一泛型的作用与定义(代码片段)

第一章深入Java泛型一、泛型的作用与定义1.1泛型的作用1.2泛型的定义1.3泛型擦除一、泛型的作用与定义1.1泛型的作用使用泛型能写出更加灵活通用的代码。泛型的设计主要参照了C++的模板,旨在能让你写出更加通用化&... 查看详情

java泛型总结(代码片段)

一:什么是泛型?泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的... 查看详情

深入java泛型(三泛型的上下边界)(代码片段)

...ds)3.3上下通配符的副作用三、泛型的上下边界?extendE是泛型的上边界, 查看详情

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

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

java中泛型的使用

...只要了解了泛型的一般使用情况就能够解决多半的问题。什么是泛型?试想一个简单的添加方法(method),如下:long,float或double类型并不能当作输入传给这个方法。如果从该方法中抽象出数据类型,就可以得到一个新的方式,... 查看详情

对java泛型的理解

一.什么是泛型:   泛型其实指得就是参数化类型,使得代码可以适应多种类型,它主要目的是指定容器要持有什么类型的对象   java的泛型是停留在编译阶段的,jvm在对待泛型数据时,依然把它们看成object类型的,在使用这些元素... 查看详情

java泛型的基本介绍和使用

现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用。泛型在java中,是一个十分重要的特性,所以要好好的研究下。一、泛型的基本概念 泛型的定义:泛型是JDK1.5的一项... 查看详情