首页 GROK CEO中文网
栏目分类

GROK CEO中文网

你的位置:GRS 中文站 > GROK CEO中文网 > JavaSE学习总结(十六)—— 泛型与泛型应用

JavaSE学习总结(十六)—— 泛型与泛型应用

发布日期:2025-01-04 10:25    点击次数:72

一、泛型概要 泛型(Generic)的本质是类型参数化,通俗的说就是用一个占位符来表示类型,这个类型可以是String,Integer等不确定的类型,表明可接受的类型。 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。 1.1、为什么需要泛型 在数据结构中有一种结构叫:栈,它的特点是:先进后出,后进先出 如:放衣服的箱子,糖葫芦 现在来模拟一个栈的数据结构 1.1.1、版本一(强类型) 结果: 缺点是不通用 1.1.2、版本二(Object弱类型) 版本一有明显的缺点,只允许存放int类型的数据,如果需要其它类型的数据怎么办法? 有人提议重新创建不同类型的栈,这样不好,因为如果需要10种不同类型的栈,则需定义10个,维护也麻烦。 使用Object也许可以解决问题,代码如下: 结果: 缺点是安全隐患(类型转换) 1.1.3、版本三(泛型) 版本二中存在类型的强制转换,如果转换的类型不匹配则会引起运行时异常,存在安全隐患,使用泛型可以解决该问题: 结果: 因为使用了泛型,兼具了版本一与版本二的优点,没有类型转换,没有安全隐患,可以适用多种不同的数据类型。 java不支持泛型数组,List或ArrayList具有泛型数组的功能。 1.2、泛型的优点 没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。 泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。 1、提高程序的安全性和可靠性使用类型更安全,指定具体类型后,Java编译器会对错误的类型在编译时被捕获,而不是在运行时当作ClassCastException展示出来,从而提高程序的安全性和可靠性 2、消除强制类型转换例如在集合里使用泛型后,从集合里取出对象后就不需要再进行强制类型转换了,这样使编写程序变得更简单,更不容易出错 3、提高代码重用率在一个类里要对不同结构类型的对象进行操作时,有的对象成员和方法的逻辑都是一样的,就是类型不一样,就有可能会造成不必要的代码重复,通过使用泛型,只需要一个Java类就可以表示不同类型的对象,从而可以大大提高代码的重用率 1.3、泛型规则 1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。 2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。 3、泛型的类型参数可以有多个。 4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。 泛型约束,约束T的类型只能是superclass的子类型 5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String"); 1.4、Java中方法的参数 java中方法参数传递的都是值,与C#区别很大,没有ref与out。 java中数据类型分为基本数据类型和引用数据类型。 基本数据类型  整型:byte,short,int,long 浮点型:float,double 字符型:char 布尔型:boolean 引用数据类型  数组 类 接口 方法的参数分为实际参数,和形式参数。 形式参数:定义方法时写的参数。 实际参数:调用方法时写的具体数值。 1.4.1、基本数据类型 结果: 从上面的结果可以看出n1与n2在调用交换方法后并没有实质交换,是因为形参是n1与n2的副本。 1.4.2、引用类型 结果: 依然没有交互 String对象做为参数传递时,走的依然是引用传递,只不过String这个类比较特殊。 String对象一旦创建,内容不可更改。每一次内容的更改都是重现创建出来的新对象。 1.4.3、结论 值传递的时候,将实参的值,copy一份给形参。 引用传递的时候,将实参的地址值,copy一份给形参。 也就是说,不管是值传递还是引用传递,形参拿到的仅仅是实参的副本,而不是实参本身。 二、自定义泛型类  示例: 结果: 6 三、自定义泛型方法 在自定义泛型类中,整个类都可以使用类型占位T,有时候只需要局部用到则可以定义泛型方法 定义泛型方法,语法如下: 示例: 结果: 说明: 1)在泛型列表中声明的泛型,可用于该方法的返回值类型声明、参数类型声明和方法代码中的局部变量的类型声明 2)类中其他方法不能使用当前方法声明的泛型 3)使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型;泛型方法除了定义不同,调用就像普通方法一样。 注意:是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。 四、通配符与泛型约束 4.1、类型通配符 类型通配符一般是使用 ? 代替具体的类型实参。 运行结果: 示例 结果:  示例:  4.2、 上界 4.2.1、通配符上界 类型通配符上限通过形如Stack<? extends Number>形式定义  示例 结果 4.2.2、占位符上界 4.2.3、多种限制 我们来分析以下这句,T extends Comparable这个是对上限的限制,Comparable< super T>这个是下限的限制,Serializable是第2个上限。一个指定的类型参数可以具有一个或多个上限。具有多重限制的类型参数可以用于访问它的每个限制的方法和域。  4.3、下界 4.3.1、通配符下界 类型通配符下限为Stack<? super Number>形式,其含义与类型通配符上限正好相反  示例: 结果: 4.3.2、占位符下界 没有,不存在... 五、类型擦除 5.1、类型擦除 Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。这个过程就称为类型擦除。如在代码中定义的List<Object>和List<String>等类型,在编译之后都会变成List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。类型擦除也是Java的泛型实现方式与C++模板机制实现方式之间的重要区别。 Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类型在编译后都会被清除掉。 Java在泛型设计上是一种“伪泛型”,存在着泛型擦除。 类型擦除是Java中泛型的实现方式。泛型是在编译器这个层次来实现的。在Java 源代码中声明的泛型类型信息,在编译过程中会被擦除,只保留不带类型参数的形式。被擦除的类型信息包括泛型类型和泛型方法声明时的形式类型参数,以及参数化类型中的实际类型信息。经过类型擦除之后,包含泛型类型的代码被转换成不包含泛型类型的代码,相当于回到了泛型被引入之前的形式,Java虚拟机在运行字节代码时并不知道泛型类型的存在。  定义好的泛型类: 被转译后: 以上面代码中的ObjectHolder泛型类为例,经过类型擦除后,由于形式类型参数T没有上界,T的所有出现将被替换成Object类型 另外使用ObjectHolder类的代码也要进行处理,如下列代码所示: 在类型擦除后,ObjectHolder类中的getObject方法的返冋值类型实际上是 Object类型,因此需要添加强制类型转换把getObject方法的返回值转换成String类型。 这些类型转换操作由编译器自动添加。由于编译器已经确保不允许使用除String类的对象之外的其他对象调用setObject方法,因此这个强制类型转换操作始终是合法的,如下列代码所示: 泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除 示例: 结果:  在JVM中的 Class 都是com.nf.math.Bean,泛型信息被擦除了。 5.2、泛型转译 示例:  因为Bean没有上界,T被转译成Object,生成如下代码: 运行结果: 泛型类被类型擦除后,相应的类型就被替换成 Object 类型呢?,不一定,如果有上界,则被替换成上界: 运行结果: 类型被转译成: 六、泛型应用 6.1、泛型与反射简化JDBCUtils工具类示例 参考:https://commons.apache.org/proper/commons-dbutils/ 已经写好的工具类: View Code 数据库: 示例: 结果: 6.2、实现泛型与反射简化JDBCUtils工具类 数据库与表的元数据就是用于描述数据库或表的信息,如表的字段(长度,类型,注释),主键,外键,约束等信息,表中的数据本来是描述客观事物的。 6.2.1、获得表的元信息方法一 示例: 结果: View Code 6.2.2、获得表的元信息方法二 代码: 测试类: 结果: 6.3、封装DbUtilis工具类 6.3.1.、查询功能 测试: 结果: View Code 6.3.2、增删改功能 View Code 6.4、JSON返回类型封装   测试: 运行结果: jsonUtils: View Code baseServlet: View Code 七、视频与示例 https://www.bilibili.com/video/av9219224/ 示例下载 八、作业 7.1、请定义一个泛型类,实现简单的List功能,可变长度的数组,可以实现foreach功能。 7.2、请定义一个泛型方法,根据指定的类型获得方法中所有的字段、方法信息。 7.3、请使用JDBC+反射+泛型实现一个可返回强类型的方法,如: 指定SQL语句、参数与类型返回一个强类型对象 View Code 7.4、指定一个数据库,生成数据库下所有的表的实体类文件 7.5、JDBC+反射+泛型实现一个简单的ORM(选作) View Code 调用: View Code  参考: https://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845938.html https://www.cnblogs.com/lwbqqyumidi/p/3837629.html