百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

深入浅出泛型,框架设计的基础 什么是框架思路

yuyutoo 2024-10-20 13:08 1 浏览 0 评论

泛型在 Java 5 出现,实现了参数化类型,主要作用是使得类或接口更加通用。比如 Java 中的容器类,通过泛型实现了对各种类型的兼容,成为极其通用的类库。如果我们要设计自己的框架,泛型基本上已经算是标配了。

类使用泛型

在类型上使用泛型,非常简单,只需要使用 <> 声明类型即可。如下 TestDO 类型声明了泛型 T,并使用 T 声明了字段 value。这样做的好处便是,TestDO 可以承载各种各样的数据,而不用定义具体的类型。这也说明了,泛型不仅可以用于类型,也可以用于字段或变量。

Java 在运行时对泛型进行擦除,运行时所有的泛型类型都退化为 Object 类型。这样的设计主要是为了保证对 Java 5 之前的代码进行兼容。尽管如此,使用泛型后,在编译阶段仍会对类型进行检查,确保使用泛型的地方都是类型正确的。

@Getter

@Setter

public

classTestDO{Tvalue;}

如下代码中,SubTestDO 传递给父类的具体类型为默认类型 Object 类型,而SubTestDOSimple 传递给父类的具体类型则是 String 类型。这两个子类都对泛型做了具体化,是泛型类型的常规使用。

/** 无泛型,即为 Object */

classSubTestDOextendsTestDO{}

/** 继承时指定父类实际类型 */

classSubTestDOSimpleextendsTestDO{}

在定义 TestDO 的子类时,子类也可以使用泛型。子类的泛型可以独自使用,也可以传递给父类。如 SubTestDOTrans 定义了泛型 T 并把 T 传递给父类,而 SubTestDOComp 定义了泛型 T 要求必须是 HashMap 的子类,但传递给父类的泛型变成了 List。

/** 继承时传递泛型 */classSubTestDOTransextendsTestDO{}

/** 继承时传递复杂类型 */

publicclassSubTestDOCompextendsSubTestDOTrans>{}

接口使用泛型可以定义适用于各种场景的通用接口,在设计模式中具有重要作用。如工厂模式就可以实现根据返回值类型自动转型,涉及到方法的泛型,在后文给出解释。

如下代码中,IGeneric 接口使用了泛型,并用泛型定义了方法。如此定义后,IGeneric 接口成为了一个通用接口,方法的入参类型与实现类或子接口对接口的定义保持一致,大大提高了通用性。接口可以继承,在继承中泛型可以有形式的变化,并定义新的泛型。

/** 普通泛型接口,泛型 T */

publicinterfaceIGeneric{publicvoidtest(Tt);}

ISubGenericSimple 接口在继承接口时,直接确定了泛型的类型为 String 类型,ISubGenericSimple 接口退化为一个普通接口,子接口或实现类不再需要对泛型进行处理。这是通过子接口对泛型进行具体化,也是架构设计中的常用手段。

/** 继承时指定泛型 */

interfaceISubGenericSimpleextendsIGeneric{}

ISubGenericTrans 接口同样使用了泛型,并把泛型传递给父接口。这种一般用于父接口的扩展,在子接口中可以定义一些特有方法,同时又完全兼容父接口的引用。

/** 继承时传递泛型 */

interfaceISubGenericTransextendsIGeneric{}

ISubGenericSubType 接口在泛型定义中,明确声明了泛型类型的范围必须是 TestDO 及其子类,这也是对父接口的一种退化,缩小了泛型的范围。这种情况一般用于比较复杂的接口体系,父接口完成顶层定义,多个子接口进行类型具体化实现分层设计。

/** 继承时指定泛型为特定类型的子类 */

interfaceISubGenericSubTypeextendsIGeneric{}

ISubGenericCompType 接口使用了一个相对复杂的泛型定义。子接口定义了泛型 T,而传递给父接口的泛型变成了 TestDO。这种接口继承方式在大型软件架构中有比较广泛的应用,通俗理解为父接口使用容器但元素类型为泛型,而子接口定义容器的元素类型,在组件化继承体系有比较明确的应用。这样的继承关系,可以确保父接口完成容器的操作方法而不用关心具体元素类型,子接口可以有少许定制逻辑甚至可以不定义方法。

/** 继承时指定复杂的泛型类型 */

interfaceISubGenericCompTypeextendsIGeneric>{}

方法使用泛型

方法也可以使用泛型,并且有很大的现实意义,在工厂模式、建造器模式中都可以使用泛型方法。

toString 方法定义了一个简单的泛型方法。在访问权限和返回值类型之间使用 声明泛型类型为 T,然后把入参类型设置为 T。在这个泛型方法中,入参类型可以是任何类型,这个通用方法可以在任何场景下使用。

/** 泛型 T 仅用于入参 */

staticStringtoString(Tt){returnnull;}

getInstance 方法不但在入参中使用了泛型,也把这个泛型作为返回值的类型。类似 getInstance 方法的定义有很多,比如 Spring 的 getBean 方法就重载了这种形式的应用。在确保方法通用性的基础上,也保证了返回值类型与入参的一致性。

/** 返回 T 类型 */

staticTgetInstance(Classclazz)throwsException{returnclazz.newInstance();}

getTestDO 方法是另一种形式的泛型方法,这里定义了返回值的泛型必须是 TestDO 及其子类。这种泛型方法常用于继承体系明确,需要对类型进行向下转型的场景。在方法内部需要对返回值进行强制转型,如果类型不匹配便会抛出类型转换异常,因此要求调用者必须了解方法的定义和使用要求。

/** 返回 TestDO 的子类类型 */

staticTgetTestDO(){return(T)newSubTestDOTrans<>();}

下面 getTestDO 的重载方法对泛型做了一定程度的退化,虽然定义了泛型 T,但这个泛型仅仅是容器的元素类型,方法的返回值是 TestDO。这种类型的泛型方法可用于复杂对象的组装,比上面的重载方法更安全。

staticTestDOgetTestDO(Tv){TestDOtestDO=newTestDO<>();testDO.setValue(v);returntestDO;}

泛型擦除

前面提到过 Java 会在运行时对泛型进行擦除,也就是抹去泛型信息,全部变为 Object 类型。因此,在运行时,TestDO 与 TestDO 在类型上并没有多大区别。虽然实际存储的 value 对象的真正类型是不同的,但是都会当做 Object 进行处理。也是因为擦除,引用类型对象时,我们可以使用 TestDO.class 却不能使用 TestDO.class。

泛型通配

前面的泛型都明确了泛型的类型为 T,并使用 T 定义字段、参数和返回值。在对具体类型依赖不那么强烈的情况下,比如,我们仅仅是要求类型是某个类型的子类即可,最终处理时使用父类类型而不依赖于子类类型,则可以使用通配符 ? 来定义泛型。

在如下代码中,set1 的元素类型为 TestDO 的子类。我们只关心 Set 中的元素是 TestDO 类型即可,并不关心实际元素是 SubTestDOSimple 还是 SubTestDOComp。而 set2 的元素类型可以是任何类型。

Setset1=newHashSet<>();

Setset2=newHashSet<>();

泛型逆变

前面提到的泛型定义用到了 extends 来确定泛型的边界,要求其必须是某个类型的子类。实际上,泛型还支持向上确定边界,也就是泛型为某个类型的父类。在如下代码中,定义了 Set 的元素类型为 SubTestDOComp 的父类。

SettestDOs=newHashSet<>();

使用泛型创建类型安全的分层结构

在架构设计中,常常涉及复杂的数据结构与设计分层,使用泛型对类型进行定义和约束,可以确保抽象层的设计有足够的通用性,同时最终产生的具体类型依然保持正确的数据类型。

比如在一个架构设计中,可能会分为抽象层、基础层、实现层三个层次。

在抽象层定义极度抽象的业务流程,需要这里的类型定义都具有较好的通用性,这时可以大量使用泛型和抽象类,只定义流程而不涉及具体类型。

在基础层定义一些基础服务,可能会在 core 层类型的基础上做一定程度的扩展,封装出多个适用范围不同的业务处理流程。在这一层,也会使用泛型,但会更加具体。

而在实现层不会再使用泛型,而是给出真正的类型,并实现具体的逻辑。

/** 抽象层,指定泛型 K,V */

abstractclassAbstractGenericImplimplementsIGeneric>{publicMapmap=newHashMap<>();}

/** 基础层,继承 AbstractGenericImpl */

classBasicGenericImplextendsAbstractGenericImpl>{@Overridepublicvoidtest(Map>data){map.putAll(data);}}

/** 实现层,继承 BasicGenericImpl */

publicclassComplexGenericImplextendsBasicGenericImpl{@Overridepublicvoidtest(Map>data){super.test(data);}}

总结

泛型在当今时代的 Java 开发中已经被广泛应用,如 Spring、MyBatis、Dubbo 等开源框架都使用了大量泛型来实现通用功能。在开发中,既要掌握开源框架的泛型使用方法,也要熟悉泛型的定义和使用,并对泛型有足够深刻的理解。如果你要开发自己的框架,那么泛型一定是标配,需要好好理解和掌握。

相关推荐

jQuery VS AngularJS 你更钟爱哪个?

在这一次的Web开发教程中,我会尽力解答有关于jQuery和AngularJS的两个非常常见的问题,即jQuery和AngularJS之间的区别是什么?也就是说jQueryVSAngularJS?...

Jquery实时校验,指定长度的「负小数」,小数位未满末尾补0

在可以输入【负小数】的输入框获取到焦点时,移除千位分隔符,在输入数据时,实时校验输入内容是否正确,失去焦点后,添加千位分隔符格式化数字。同时小数位未满时末尾补0。HTML代码...

如何在pbootCMS前台调用自定义表单?pbootCMS自定义调用代码示例

要在pbootCMS前台调用自定义表单,您需要在后台创建表单并为其添加字段,然后在前台模板文件中添加相关代码,如提交按钮和表单验证代码。您还可以自定义表单数据的存储位置、添加文件上传字段、日期选择器、...

编程技巧:Jquery实时验证,指定长度的「负小数」

为了保障【负小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【负小数】的方法。HTML代码<inputtype="text"class="forc...

一篇文章带你用jquery mobile设计颜色拾取器

【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...

编程技巧:Jquery实时验证,指定长度的「正小数」

为了保障【正小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【正小数】的方法。HTML做成方法<inputtype="text"class="fo...

jquery.validate检查数组全部验证

问题:html中有多个name[],每个参数都要进行验证是否为空,这个时候直接用required:true话,不能全部验证,只要这个数组中有一个有值就可以通过的。解决方法使用addmethod...

Vue进阶(幺叁肆):npm查看包版本信息

第一种方式npmviewjqueryversions这种方式可以查看npm服务器上所有的...

layui中使用lay-verify进行条件校验

一、layui的校验很简单,主要有以下步骤:1.在form表单内加上class="layui-form"2.在提交按钮上加上lay-submit3.在想要校验的标签,加上lay-...

jQuery是什么?如何使用? jquery是什么功能组件

jQuery于2006年1月由JohnResig在BarCampNYC首次发布。它目前由TimmyWilson领导,并由一组开发人员维护。jQuery是一个JavaScript库,它简化了客户...

django框架的表单form的理解和用法-9

表单呈现...

jquery对上传文件的检测判断 jquery实现文件上传

总体思路:在前端使用jquery对上传文件做部分初步的判断,验证通过的文件利用ajaxFileUpload上传到服务器端,并将文件的存储路径保存到数据库。<asp:FileUploadI...

Nodejs之MEAN栈开发(四)-- form验证及图片上传

这一节增加推荐图书的提交和删除功能,来学习node的form提交以及node的图片上传功能。开始之前需要源码同学可以先在git上fork:https://github.com/stoneniqiu/R...

大数据开发基础之JAVA jquery 大数据java实战

上一篇我们讲解了JAVAscript的基础知识、特点及基本语法以及组成及基本用途,本期就给大家带来了JAVAweb的第二个知识点jquery,大数据开发基础之JAVAjquery,这是本篇文章的主要...

推荐四个开源的jQuery可视化表单设计器

jquery开源在线表单拖拉设计器formBuilder(推荐)jQueryformBuilder是一个开源的WEB在线html表单设计器,开发人员可以通过拖拉实现一个可视化的表单。支持表单常用控件...

取消回复欢迎 发表评论: