泛型(泛型擦除)

简介: 泛型1.什么是泛型2.泛型类、泛型接口、泛型方法3.为什么要使用泛型,泛型的好处4.使用泛型注意点5.泛型擦除

泛型


1.什么是泛型

2.泛型类、泛型接口、泛型方法

3.为什么要使用泛型,泛型的好处

4.使用泛型注意点

5.泛型擦除

 

1.什么是泛型

1.1泛型概念:Java泛型是J2 SE1.5中引入的一个新特性,其本质是参数化类型,也就是说所操作的数据类型被指定为一个参数(type parameter),

这种参数类型可以用在接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

1.2本质:参数化类型

1.3语法:<T>,  T 称为类型占位符,表示一种引用类型。

1.3 泛型定义(泛型类、泛型方法(泛型方法返回值是泛型的,泛型方法在普通类和泛型类里)):


10、泛型的定义是<T>(带尖角号的T),
例如定义一个泛型类:public class Stu<T>{ }
定义一个泛型方法(不在泛型类里):publilc <T> void testMethod() { }
或定义一个返回值类型是泛型的方法(不在泛型类里): public <T> T testMethod2(){return null}
注意,(在泛型类里 的返回值是泛型的方法)在定义了泛型类之后,在该类里想要返回值类型是一个泛型的方法(),不用再<T>定义该方法是泛型啦,直接可以使用泛型的T: public T testMethod3(){return null}


1.4特点:(1)编译时即可检查,非运行时抛出异常;

     (2)访问时不需要类型转换(拆箱);

     (3)不同泛型之间不能相互赋值,泛型不存在多态。

 

对于泛型特点(1)举个例子 : 没有使用泛型时的异常抛出

public class MyGenericTest {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(123);       //添加Integer对象
        list.add("zifu");    //添加String对象
        list.add(1.22);      //添加Double对象
        for(Object object: list) {
            //!!!使用,例如要进行运算使用
            Double num = (Double)object;
            System.out.println(num);
        }
    }
}


结果:Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double

   at MyGenerics.MyGenericTest.main(MyGenericTest.java:28)

分析一下:编译通过,但是运行提示异常,类型转换异常,就是String类型不能转换为Double类型。我们在使用 list.add() 方法时,根据提示知道凡是Object对象都可以添加进去,但是要使用的时候忘了添加过什么类型的对象进去,根据提示强转过,但是由于添加进去一些类型不同的,强转可以在编译时通过,运行时异常抛出了。

这里就可以体现泛型的好处之一了:防止类型转换异常,提高代码的安全性。


6.png


对于泛型特点(2)访问时不需要类型转换(拆箱),举例子List<String>  list =  new ArrayList<String>();

查看ArrayList的访问4方法get()源码,看到返回值类型是泛型E,所以我们获取时就不用强转了。


7.png


 //访问时不需要类型转换


package MyGenerics;
import java.util.ArrayList;
import java.util.List;
public class MyGenericTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("dingdong");      
        list.add("zifu");  
        list.add("meimei");    
        for(int i = 0; i < list.size(); i++) {
            //!!!使用
            String str = list.get(i);  //访问时不需要类型转换
            System.out.println(str);
        }
    }
}


对于泛型特点(3)不同泛型之间不能相互赋值,举例


8.png


 对于泛型特点(3)泛型不存在多态,举例



9.png


另外这里报错原因是:Type mismatch: cannot convert from ArrayList<Integer> to ArrayList<Number>,类型不匹配的愿意

ps:泛型没有多态:是因为人家设计出来的初心就是为了提高代码重用,类型的转换都是自动和隐式的。(所以人家的真心不允许被辜负,就没多态了)

 

2.泛型类、泛型接口、泛型方法

2.1泛型类

语法:类名<T,........>

举例:

package MyGenerics;
import java.util.List;
//Generic类,泛型类
//语法:类名<T>
public class MyGeneric <T>{
    //添加属性(泛型属性变量)
    T t;
    //添加方法(泛型参数)
    public void show(T t) {
        System.out.println(t);
    }
    //添加方法(泛型做为返回值)
    public T getT() {
        return t;
    }
}


2.2泛型接口与泛型类相似,不举例子了

语法:接口名<T, .......>

2.3泛型方法

语法:[ 修饰符] <T> 返回值类型 方法名([参数列表])

 

2.4.疑惑,为什么有泛型类了,还要有泛型方法,泛型类与泛型方法有什么区别,泛型方法有什么好处?

为什么要使用泛型方法呢?(想换类型时,考虑方法的调用方便的好处,而类需要实例化)

因为泛型类要在实例化的时候就指明类型,如果想换一种类型,不得不重新new一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活。

 

3.为什么要使用泛型,泛型的好处:

3.1泛型的好处

答:提高代码重用性,防止类型转换异常,提高代码的安全性。(也可以加上泛型特点(1)(2))

3.2泛型类的好处

答:使用泛型类可以解决重复业务的代码的复用问题,也就是业务颗粒的复用,同时使用泛型类型在编译阶段就可以确定,并发现错误,类型的转换都是自动和隐式的,提高了代码的准确率和复用率。

 

4.使用泛型注意点:

4.1不同泛型之间不能相互赋值,泛型不存在多态((检查机制)泛型特点(3))

4.2要注意泛型擦除

4.3不能实例化泛型,例如 T t = new T();  理由:泛型擦除T都没了

4.4泛型不能是基本类型(泛型本质是一种引用类型),还有考虑到泛型擦除后的类型,例如为Object类型时,Object不能存储基本类型int,double...

 

5.泛型擦除

 

5.1 泛型擦除概念: 类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。

简单理解:在编译期间,所有的泛型信息都会被擦除掉。例如代码中定义的List<Object>和List<String>等类型,在编译后都会变成List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。

 

5.2 由于泛型擦除出现的错误举例:


10.png


报错原因:Erasure of method MyGeneric(ArrayList<String>) is the same as another method in type MyGeneric<T>,

Erasure of method MyGeneric(ArrayList<Integer>) is the same as another method in type MyGeneric<T>

类型擦除的原因,擦除后        //方法重载,都变成了

 public MyGeneric(ArrayList  arrayList) {

       

   }

 

完美解释此处问题,但是却勾起小伙伴的另外一个问题,类型擦除了,为什么不同泛型之间不能相互赋值!!

因为检查机制的存在,编译器的工作是这样子滴:首先进行类型检查,检查类型不同,报错!如果类型相同,再进行类型擦除啦!!!(即进入擦除阶段,需要通过检查那一关)

举个例子,购买的衣服,需要相关人员先进行质量合格等方面的检查,检查通过,进入商城,消费者购买完撕掉了吊牌。。。。。

目录
相关文章
|
消息中间件 SQL 存储
超详细的RabbitMQ入门,看这篇就够了!
RabbitMQ入门,看这篇就够了
221277 69
|
Java Maven
Maven - 解决Maven下载依赖包速度慢问题
通常我们会因为下载jar包速度缓慢而苦恼,这十分影响开发效率,以及程序员的心情,在IDE下载jar时,无法对IDE做任何动作,只能大眼对小眼。 下载jar速度慢究其原因就是因为很多资源都是国外的,我们下载一个小文件几乎就跨越了一个太平洋那么远,那么有什么方法可以让下载速度变快呢?   其实方法...
8284 0
|
存储 大数据 关系型数据库
【数据库三大范式】让我们来聊一聊数据库的三大范式和反范式设计
数据库三大范式是指数据库设计中的规范化原则,它们分别是第一范式(1NF)第二范式(2NF)和第三范式(3NF)。第一范式(1NF)第二范式(2NF)第三范式(3NF)
|
6月前
|
安全 数据可视化 数据管理
国内主流低代码开发平台解析与盘点
本文系统梳理了当前主流低代码开发平台,涵盖通用型、垂直行业型、流程自动化型、数据库驱动型及移动应用优先型平台,分析了其功能特点、技术架构与适用场景,并从企业需求、规模、预算及技术支持等方面提供选型建议。文章指出,低代码平台正加速与AI、边缘计算等技术融合,推动企业数字化转型。
367 1
|
11月前
|
存储 Java 编译器
Java泛型类型擦除以及类型擦除带来的问题
本文主要讲解Java中的泛型擦除机制及其引发的问题与解决方法。泛型擦除是指编译期间,Java会将所有泛型信息替换为原始类型,并用限定类型替代类型变量。通过代码示例展示了泛型擦除后原始类型的保留、反射对泛型的破坏以及多态冲突等问题。同时分析了泛型类型不能是基本数据类型、静态方法中无法使用泛型参数等限制,并探讨了解决方案。这些内容对于理解Java泛型的工作原理和避免相关问题具有重要意义。
626 0
|
弹性计算
为什么我在幻兽帕鲁里走路会回弹很卡顿
你可以尝试执行一段脚本,去掉游戏启动参数里的 -useperfthreads -NoAsyncLoadingThread -UseMultithreadForDS 来尝试解决人物回弹的问题。
5758 0
|
存储 Java 编译器
Java泛型类型擦除以及类型擦除带来的问题
泛型擦除是指Java编译器在编译期间会移除所有泛型信息,使所有泛型类型在运行时都变为原始类型。例如,`List&lt;String&gt;` 和 `List&lt;Integer&gt;` 在JVM中都视为 `List`。因此,通过 `getClass()` 比较两个不同泛型类型的 `ArrayList` 实例会返回 `true`。此外,通过反射调用 `add` 方法可以向 `ArrayList&lt;Integer&gt;` 中添加字符串,进一步证明了泛型信息在运行时被擦除。
309 2
|
算法 固态存储 架构师
【最佳实践】一文掌握并应用Elasticsearch中的GC实现垃圾日志处理
你是否了解 GC 日志?以及如何通过GC,来解决何时找到、何时处理以及如何处理垃圾日志?
2996 0
【最佳实践】一文掌握并应用Elasticsearch中的GC实现垃圾日志处理
|
SQL 存储 缓存
maxcompute的特点
【5月更文挑战第5天】maxcompute的特点
433 6
|
存储 人工智能 运维
spring国际化 - i18n
spring国际化 - i18n
347 0