广告
返回顶部
首页 > 资讯 > 精选 >Java泛型的概念和Type类型体系
  • 423
分享到

Java泛型的概念和Type类型体系

2023-06-16 02:06:52 423人浏览 安东尼
摘要

本篇内容主要讲解“Java泛型的概念和Type类型体系”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java泛型的概念和Type类型体系”吧! 1 JAVA的Type类型体系先了解下j

本篇内容主要讲解“Java泛型的概念和Type类型体系”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java泛型的概念和Type类型体系”吧!

 1 JAVA的Type类型体系

先了解下java的Type类型体系(类的类=>类型),Type是所有类型(原生类型-Class、参数化类型-Parameterizedtype、数组类型-GenericArrayType、类型变量-TypeVariable、基本类型-Class)的共同接口;前两篇反射和注解讲到的Class就是Type的一实现类

Java泛型的概念和Type类型体系

  • Type下面又有四个子接口类ParameterizedType、TypeVariable、GenericArrayType、WildcardType

    • List

      表示泛型,E是TypeVariable类型,List则是ParameterizedType(参数化类型),List里的String称为实际参数类型
    • 具体化泛型中的类型时,可以使用 ? extends 或 ? super来表示继承关系;如List,而里面的 ?  称为通配符类型WildcardType

    • GenericArrayType  表示一种元素类型是ParameterizedType(参数化类型)或者TypeVariable(类型变量)的数组类型,如T[] 或者 List

      []
  • 注解是jdk1.5才出现了的,为了表示被注解的类型的,加入AnnotatedElement类型,字面意思就是被注解的元素。JDK1.8又有了AnnotatedType将Type和被注解元素的概念关联起来。

  • Java泛型的概念和Type类型体系

  • AnnotatedType也有四个子接口,和Type的四个子接口一一对应,如:ParameterizedType类型被注解则被编译器解析成AnnotatedParameterizedType:  @AnTest("list")List

    list

2 泛型的概念

  • Java  泛型(generics)是JDK1.5中引入的一个新特性,其本质是参数化类型,解决不确定具体对象类型的问题;其所操作的数据类型被指定为一个参数(type  parameter)这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法

泛型: 把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型

3 泛型类和泛型方法的示例

  • 泛型类的定义

public class MainTest<T> {     private  T param; } public static void main(String[] args){         MainTest<String> data = new MainTest<String>(){};         ParameterizedType genType1 = (ParameterizedType)data.getClass().getGenericSuperclass();   }
  • 泛型方法的定义

public class MainTest{     public static void main(String[] args){         printData("siting");     }     static  <T> T printData(T t){         System.out.println(t);         return t;     } }

接口和抽象类都可以使用泛型

4 类型擦除

  • 创建泛型的实例时,JVM是会把具体类型擦除的;编译生成的字节码中不包含泛型中的类型参数,即ArrayList

    和ArrayList都擦除成了ArrayList,也就是被擦除成"原生类型",这就是泛型擦除
public class MainTest {     public static void main(String[] args){         List<String> strArr  = new ArrayList<>();         List<Integer> intArr  = new ArrayList<>();         Type strClazz = strArr.getClass();         Type intClazz = intArr.getClass();     } }

Java泛型的概念和Type类型体系

  • 查看编译后的字节码文件是如何表示的: idea菜单 -> view -> show ByteCode

public class MainTest<T> {     T param;     public static void main(String[] args){         MainTest<String> test = new MainTest<>();         test.setParam("siting");     }     public T getParam() {  return param;   }     public void setParam(T param) {  this.param = param;  } } public class com/MainTest {   ...省略   public static main([Ljava/lang/String;)V    L0     LINENUMBER 7 L0     NEW com/MainTest     DUP     INVOKESPECIAL com/MainTest.<init> ()V     ASTORE 1    L1     LINENUMBER 8 L1     ALOAD 1     LDC "siting"     // 调用类型擦除后的setParam(Object)     INVOKEVIRTUAL com/MainTest.setParam (Ljava/lang/Object;)V    L2    ...省略//getParam 的返回值是Object   public getParam()Ljava/lang/Object;    L0     LINENUMBER 10 L0     ALOAD 0     GETFIELD com/MainTest.param : Ljava/lang/Object;     ARETURN    ...省略//setParam 的入参是Object   public setParam(Ljava/lang/Object;)V    L0     LINENUMBER 11 L0     ALOAD 0     ALOAD 1     PUTFIELD com/MainTest.param : Ljava/lang/Object;     RETURN    ... }

可以看出T(String)都被转换为Object类型,最初的初始化的String不见了

5 泛型的继承

  • 子类可以指定父类的泛型参数,可以是已知类(Integer、String等),也可以用子类自己的泛型参数指定

  • 泛型被继承时,且指定父类泛型参数,则额外生成的ParameterizedType类型作为子类的父类;如果没有指定父类泛型参数,则直接继承原生类型

public class MainTest<T> {     T param;     static public class SubTest1 extends MainTest<String>{}     static public class SubTest2<R> extends MainTest<R>{}     //SubTest3继承的时原生类型     static public class SubTest3 extends MainTest{} }

Java泛型的概念和Type类型体系

6 泛型变量TypeVariable

  • (先临时定义一个名称,Test

    里的E为泛型参数);泛型变量TypeVariable:泛型的泛型参数就是TypeVariable;当父类使用子类的泛型参数指定自身的泛型参数时;或者泛型属性定义在泛型类A中,并使用泛型类A的泛型参数T时,其泛型参数都会被编译器定为泛型变量TypeVariable,而不是被擦除
public class MainTest<T> {     List<T> param;     public static void main(String[] args) throws Exception{         Class clazz =  MainTest.class;         TypeVariable[] typeVariable = clazz.getTypeParameters();         // 1         Field field = clazz.getDeclaredField("param");         ParameterizedType arrayType = (ParameterizedType)field.getGenericType();         // interface List<E> 的泛型类型E被T,具体化,因此其被识别为 TypeVariable         TypeVariable variable1 = (TypeVariable)arrayType.getActualTypeArguments()[0];         // 2         ParameterizedType type = (ParameterizedType)SubTest.class.getGenericSuperclass();         TypeVariable variable2 = (TypeVariable)type.getActualTypeArguments()[0];     }     static class SubTest<R> extends MainTest<R>{} }

7 参数化类型ParameterizedType

public interface ParameterizedType extends Type {     //获取实际参数,List<String>里的String; 如果是List<T>则是TypeVariable类型     Type[] getActualTypeArguments();      // 获取原始类型List<String> -> List<E>     Type getRawType();       Type getOwnerType(); }
  • 需要注意的点,我们不能直接获取指定具体参数的泛型的类型,如Class clazz =  List

    .class编译时不通过的;还有就是直接通过泛型类new创建的对象,其Class并非ParameterizedType类型,而是泛型本身的class,示例如下
public class MainTest<T> {     public static void main(String[] args){         MainTest<String> str = new MainTest<String>();         Class variable = str.getClass();         Type genType1 = variable.getGenericSuperclass();     } }

Java泛型的概念和Type类型体系

  • 被具体参数化的泛型才能被编译器识别为ParameterizedType类型,有三种方式获取ParameterizedType类型

// 1 子类继承泛型时,指定具体参数(可以是String等已知类型,也可以是子类的泛型参数) // 2 获取在类内部定义的泛型属性,需指定具体泛型参数 // 3 局部代码,可以通过泛型的匿名内部子类(需指定具体泛型参数)获取ParameterizedType类型 public class MainTest<T> {     List<T> list;     public static void main(String[] args) throws NoSuchFieldException {         SubTest<String> str = new SubTest<>();         // 方式一         Class variable = str.getClass();         // 父类是(521)ParameterizedType类型         ParameterizedType genType = (ParameterizedType)variable.getGenericSuperclass();         // (521)ParameterizedType类型的原生类型是(479)class com.MainTest         Type clazz = genType.getRawType();         //MainTest.class 的原生类型是 (479)class com.MainTest         Class rawClazz = MainTest.class;          //方式二,泛型属性         Field field = rawClazz.getDeclaredField("list");         //属性list 类型是(546)ParameterizedType类型List<T>         ParameterizedType fieldType = (ParameterizedType)field.getGenericType();          // 方式三         MainTest<String> sub3 = new MainTest<String>(){};         // clazz3是匿名子类         Class clazz3 =  sub3.getClass();         //父类是(555)ParameterizedType类型         ParameterizedType genType3 = (ParameterizedType) clazz3.getGenericSuperclass();         // (555)ParameterizedType类型的原生类型是(479)class com.MainTest         Type type3 = genType3.getRawType();     }     public static class SubTest<R> extends MainTest<R>{ } }

Java泛型的概念和Type类型体系

8 通配符(WildcardType)

无边界通配符:无界通配符 ? 可以适配任何引用类型:

  • 当方法参数需要传入一个泛型时,而且无法确定其类型时。直接使用无具体泛型变量的泛型,容易造成安全隐患;若在方法代码里进行类型转换,极容易出现ClassCastException错误

  • 那泛型变量用Object代替不就行了?但是泛型类+具体参数转变的ParameterizedType(参数化类型)是不存在继承关系;即Object是String的父类,但是List  和List

    的类型是不同的两个ParameterizedType,不存在继承关系。于是有了类型通配符 ?
public static void print(List list){}  ----->>> public static void print(List<?> list){}

Java泛型的概念和Type类型体系

  • 无界通配符可以匹配任意类型;但是在使用?时,不能给泛型类的变量设置值,因为我们不知道具体类型是什么;如果强行设置新值,后面的读容易出现ClassCastException错误。因此编译器限制了**通配符  ?**的泛型只能读不能写

上界限定通配符 < ? extends E>

  • 想接收一个List集合,它只能操作数字类型的元素【Float、Integer、Double、Byte等数字类型都行】,怎么做?可以使用List,表明List里的元素都是Number的子类

  • public static void print(List<? extends Number> list) {         Number n = new Double("1.0");         list.add(n);         Number tmp = list.get(0);     }

Java泛型的概念和Type类型体系

  • 图片里可以看出,存在上界通配符,因为具体类型不确定,也是只能读不能写的

下界限定通配符 < ? super E>

class Parent{ } class Child extends Parent{ } public class MainTest<T> {     T param;     public static void main(String[] args){         MainTest<? super Child> parent_m = new MainTest<>();         parent_m.setParam(new Child());         Object parent = parent_m.getParam();     }     public T getParam() {  return param;  }     public void setParam(T param) {  this.param = param; } }

Java泛型的概念和Type类型体系

  • 如果定义了通配符是谁的父类,则是下界限定通配符;此类通配符可读可写,转成任意父类都不会出现ClassCastException错误。

  • 个人猜想:难道是因为通配符和上界限定通配符的泛型  向下转型容易出现ClassCastException错误,而下界限定通配符向上转型不会出现ClassCastException错误,因此java规范限制前者编译出错,而后面编译通过?

9 泛型数组(GenericArrayType)

public interface GenericArrayType extends Type {     //获得这个数组元素类型,即获得:A<T>(A<T>[])或  T(T[])     Type getGenericComponentType(); }
  • GenericArrayType,泛型数组,描述的是ParameterizedType类型以及TypeVariable类型数组,即形如:Test

    [][]、T[]等,是GenericArrayType的子接口
public class MainTest<T> {     T[] param;     public static void main(String[] args) throws Exception{         Class clazz =  MainTest.class;         Field field = clazz.getDeclaredField("param");         GenericArrayType arrayType = (GenericArrayType)field.getGenericType();         TypeVariable variable = (TypeVariable) arrayType.getGenericComponentType();     } }

Java泛型的概念和Type类型体系

到此,相信大家对“Java泛型的概念和Type类型体系”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: Java泛型的概念和Type类型体系

本文链接: https://www.lsjlt.com/news/282125.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java泛型的概念和Type类型体系
    本篇内容主要讲解“Java泛型的概念和Type类型体系”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java泛型的概念和Type类型体系”吧! 1 JAVA的Type类型体系先了解下j...
    99+
    2023-06-16
  • Java泛型中逆变和协变的概念
    本篇内容主要讲解“Java泛型中逆变和协变的概念”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java泛型中逆变和协变的概念”吧!正文OK,今天5分钟短文就让咱们聊一聊逆变和协变这俩个概念。1、...
    99+
    2023-06-16
  • 和解析Java虚拟机概念及数据类型
    今天就跟大家聊聊有关和解析Java虚拟机概念及数据类型,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。你对Java虚拟机的概念是否熟悉,这里向大家描述一下,Java虚拟机是一个想象中的...
    99+
    2023-06-17
  • java向上转型和向下转型的概念是什么
    Java中的向上转型(Upcasting)和向下转型(Downcasting)是指对象在继承关系中的类型转换。向上转型是指将子类对象...
    99+
    2023-09-14
    java
  • java泛型类型的调用和实例化介绍
    本篇内容主要讲解“java泛型类型的调用和实例化介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java泛型类型的调用和实例化介绍”吧!1、泛型调用类似于普通方法调用,但你不是把参数传递给方法...
    99+
    2023-06-20
  • LINQ查询和泛型类型的关系是什么
    本篇内容介绍了“LINQ查询和泛型类型的关系是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!LINQ查询基于泛型类型,在 .NET Fr...
    99+
    2023-06-17
  • 接口回调的概念和典型例程(java和kotlin)
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、什么是接口回调?二、为什么要使用接口回调三、在JAVA和kotlin中几个接口回调的实例1.java实例2.kotlin实例 三、总结 ...
    99+
    2023-12-22
    android
  • 详解java 中泛型中的类型擦除和桥方法
    在Java中,泛型的引入是为了在编译时提供强类型检查和支持泛型编程。为了实现泛型,Java编译器应用类型擦除实现:       1、  用类型参数(type parame...
    99+
    2023-05-31
    java 泛型 桥方法
  • 数据类型和接口的概念在 Java 框架中的实际应用。
    在 Java 框架中,数据类型和接口是非常重要的概念,它们的正确使用可以大大提升程序的效率和可读性。下面我们就来探讨一下这两个概念在 Java 框架中的实际应用。 一、数据类型在 Java 框架中的实际应用 Java 是一种强类型语言,因此...
    99+
    2023-10-13
    框架 数据类型 接口
  • 数据类型是Python、Laravel和Spring中最重要的概念吗?
    随着计算机技术的不断发展,数据处理已经成为了各种应用程序开发的核心。而不同的编程语言和框架对于数据类型的处理方式也有所不同,Python、Laravel和Spring作为三个不同的技术体系,在数据类型方面的处理也有着各自的特点。 那么,数...
    99+
    2023-09-19
    数据类型 laravel spring
  • Python基础数据类型中tuple元组的概念和用法
    本篇内容主要讲解“Python基础数据类型中tuple元组的概念和用法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python基础数据类型中tuple元组的概念和用法”吧!目录元组简单介绍声明...
    99+
    2023-06-20
  • Java编程算法学习笔记:如何理解数据类型的概念?
    在Java编程中,数据类型是一个非常基础的概念,它在程序中扮演着非常重要的角色。在Java中,数据类型可以分为两大类:基本数据类型和引用数据类型。其中,基本数据类型包括boolean、byte、short、int、long、float、d...
    99+
    2023-06-17
    编程算法 学习笔记 数据类型
  • Java编程算法的学习笔记:如何理解数据类型的概念?
    在Java编程中,数据类型是一个非常基础的概念。它决定了你能够使用哪些数据以及如何使用这些数据。因此,学习Java编程算法的过程中,理解数据类型的概念是非常重要的。 Java中的数据类型分为两种:基本数据类型和引用数据类型。基本数据类型包...
    99+
    2023-06-17
    编程算法 学习笔记 数据类型
  • 数据类型是Python和Laravel中的重要概念,你了解它们吗?
    在程序设计中,数据类型是非常重要的概念。它定义了数据的种类和在计算机中所占用的内存空间。Python和Laravel是两个流行的编程语言,它们都有自己的数据类型系统。在本文中,我们将探讨Python和Laravel中的数据类型,包括它们的...
    99+
    2023-10-02
    laravel load 数据类型
  • Java数据结构之图的基础概念和数据模型详解
    目录图的实际应用图的定义及分类图的相关术语图的存储结构邻接矩阵邻接表图的实现图的API设计代码实现图的实际应用 在现实生活中,有许多应用场景会包含很多点以及点点之间的连接,而这些应用...
    99+
    2022-11-13
    Java数据结构 图 Java 图
  • oracle中的数据类型和java中的数据类型的对应关系
    oracle中的数据类型和java中的数据类型的对应关系 oracle 中Number 分为两种 1.Number 2.Number(10,2)第一种对应的是java中的整形 int l...
    99+
    2023-09-11
    java oracle 数据库
  • 如何解析 Linux 中“一切都是文件”概念和相应的文件类型
    今天就跟大家聊聊有关如何解析 Linux 中“一切都是文件”概念和相应的文件类型,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在 Unix 和它衍生的比如 Linux  系...
    99+
    2023-06-16
  • java方法泛型入参T和String的重载关系详解
    目录方法泛型入参T和String的重载关系重载的基本知识不在这里讨论了重载遇到泛型的问题反复求证,得出以下结论方法泛型入参T和String的重载关系 重载的基本知识不在这里讨论了 重...
    99+
    2022-11-13
  • Java虚拟机的体系结构和内存模型是什么
    这篇文章主要介绍“Java虚拟机的体系结构和内存模型是什么”,在日常操作中,相信很多人在Java虚拟机的体系结构和内存模型是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java虚拟机的体系结构和内存模型...
    99+
    2023-06-17
  • java反射遍历实体类属性和类型,并赋值和获取值的简单方法
    实例如下:import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;i...
    99+
    2023-05-31
    java 反射 实体类
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作