解释型语言和编译型语言的区别_从泛型的使用情况看出你对语言的理解程度(2)...

709f16729d5b31268fa787f28ed25192.png

上篇我们提到:Java中的泛型是不可变的,可以通过<? extends E>实现了泛型的协变,<? super E>实现泛型的逆变。从泛型的使用情况看出你对语言的理解程度(1)

今天我们来讲讲泛型单例工厂,在之前的推文中也有推送过单例模式的实现,但是不是用泛型实现的,这次我们先讲一个泛型单例的例子,然后再讲泛型单例工厂会更好理解一些。

首先定义一个泛型接口,里面包含一个apply方法:

public interface Money<T> { T apply(T args);
}

然后我们需要一种String类型的数据进行apply操作的单例对象。按惯性思维,我们会这么实现。

public class PaperMoney implements Money<String>{private static PaperMoney paperInstance = new PaperMoney();private PaperMoney(){} public PaperMoney getInstance() {return paperInstance;}@Overridepublic String apply(String args) {      return args;}
}

在工程需求复杂的情况下,这种模式没有考虑到代码的扩展性,当未来需要对Integer对象数据进行apply操作呢?再写一个类吗?这明显是过于麻烦了。这时候就需要再结合工厂的设计模式了。

泛型单例工厂

在工厂中,会产生不同参数类型的Money对象,在结合static的特性,实现复用生成的Money对象。

public class MoneyImp {//Money是类似函数式接口实现private static Money<Object> IDENTITY_FUNCTION = arg -> String.valueOf(arg.hashCode());@SuppressWarnings("unchecked")public static <T> Money<T> getMoneyInstance() {return (Money<T>) IDENTITY_FUNCTION;}public static void main(String[] args) {String[] strings = { "one", "five", "ten" };Money<String> paperMoney = getMoneyInstance();for (String s : strings) {System.out.println(paperMoney.apply(s));}Integer[] numbers = { 1, 2, 3 };Money<Integer> coinMoney = getMoneyInstance();for (Integer n : numbers)System.out.println(coinMoney.apply(n));JSONObject[] jsonObjects = {JSON.parseObject("{hah:1}")};Money<JSONObject> objMoney = getMoneyInstance();for (JSONObject n : jsonObjects)System.out.println(objMoney.apply(n));}
}

上面的代码中Money接口其实是仿照Java8中的Function函数式接口定义的,或者说是仿照Function接口的子类接口:UnaryOperator。关于Function函数式接口可以看今天的另一篇推文介绍。简单的说,Function就是实现了这样的一个公式:y=f(x),而UnaryOperator实现的是:x=f(x)。

也就是说IDENTITY_FUNCTION 其实实现的是x=String.valueOf(f(x))的功能。在这里我们将传进来的x获取其hashCode,然后转换成字符串形式返回回去。同时由于IDENTITY_FUNCTION 是一个Money<Object> 。用Object接收返回的String(f(x))所以是合理的(父类引用指向子类对象)所以,还是可以把IDENTITY_FUNCTION 看作是x=f(x)。

arg -> String.valueOf(arg.hashCode());这个函数由于hashCode() 属于Object,所以任何类调用都不会报错。否则很容易报错,这里要多注意。

如果没有getMoneyInstance() 方法,而是直接把IDENTITY_FUNCTION 赋值给paperMoney 即:

Money<String> paperMoney = IDENTITY_FUNCTION();

则会报编译错误:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Stringat com.ltjh.imports.job.MoneyImp.main(MoneyImp.java:27)

这个很明显,因为泛型是不可以协变的。所以我们需要一个静态工厂方法:getMoneyInstance()。

所有重点来了:

getMoneyInstance() 方法的作用,则是作为一个静态工厂方法用于获取我们编写的IDENTITY_FUNCTION 函数。代码中由于对IDENTITY_FUNCTION 进行了强制类型转换return (Money<T>) IDENTITY_FUNCTION; 所以需要添加unchecked 转换警告,因为编译器并不知道Money<Object> 的每个都是Money<T> ,但是因为IDENTITY_FUNCTION 表示的是x=f(x),所以我们可以确定返回的就是Money<T> 。这是类型安全的。一旦我们这样做了,代码编译就不会出现错误或警告。

于是,我们就可通过getMoneyInstance() 获取到处理特定类型的Money 如:paperMoney 、coinMoney 和 objMoney 。也就实现了一个泛型的单例工厂。

上面代码的输出结果如下:

110182
3143346
114717
1
2
3
103054

《Effective Java》中对泛型单例工厂的描述如下:

有时,你需要创建一个对象,该对象是不可变的,但适用于许多不同类型。因为泛型是由擦除实现的,所以你可以为所有需要的类型参数化使用单个对象,但是你需要编写一个静态工厂方法,为每个请求的类型参数化重复分配对象。这种模式称为泛型单例工厂,可用于函数对象,如 Collections.reverseOrder,偶尔也用于集合,如 Collections.emptySet。

最后再提一点关于擦除的,由于Java泛型是由擦除实现的,所以,其实上面的代码在便后后类似于这样:

public class MoneyImp {//Money是类似函数式接口实现private static Money IDENTITY_FUNCTION = arg -> String.valueOf(arg.hashCode());@SuppressWarnings("unchecked")public static Money getMoneyInstance() {return IDENTITY_FUNCTION;}public static void main(String[] args) {String[] strings = { "one", "five", "ten" };Money paperMoney = getMoneyInstance();for (String s : strings) {System.out.println(paperMoney.apply(s));}Integer[] numbers = { 1, 2, 3 };Money coinMoney = getMoneyInstance();for (Integer n : numbers)System.out.println(coinMoney.apply(n));JSONObject[] jsonObjects = {JSON.parseObject("{hah:1}")};Money objMoney = getMoneyInstance();for (JSONObject n : jsonObjects)System.out.println(objMoney.apply(n));}
}

运行结果和前面的一样且不报错。那我们为什么还这么费劲用个泛型搞得云里雾里的呢?因为我们想要获取到专门处理某一种类型的Money:paperMoney 、coinMoney 、objMoney 。如果不适用泛型,用上面的代码,那么这三个paperMoney 、coinMoney 、objMoney 其实是没有限制的,没办法装门处理某一种特定类型啦。

好了,就到这里,不理解的朋友可以留言一起讨论哦~

关注公众号获取更多内容,有问题也可在公众号提问哦

9b0b09927d3ee4402523ddf9f130935f.png

强哥叨逼叨

叨逼叨编程、互联网的见解和新鲜事

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/551856.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

泸州职业技术学院计算机单招试题,2021年泸州职业技术学院单招英语考试模拟试题库...

2021年高职单招升学一对一咨询高职单招郭老师:15683905627(微信)单招考试考什么单招专业技能考试文化统考;文化统考科目包括语文、数学、英语、专业综合理论。单招考试形式&#xff1a;专业技能考试文化统考。专业技能考试形式和内容由各专业大类联考委确定。文化统考科目为语文…

sata接口测试软件,如何查看电脑是否支持USB 3.0?Hwinfo32检测SATA端口的方法

Hwinfo32检测SATA端口有很多效用&#xff0c;其中我们查看该SATA是否支持USB 3.0就是一个判断&#xff0c;更多的信息是为了了解SATA目前已经可使用的和在使用的端口情况&#xff0c;具体方法可以查看下文中的方法进行判断。Hwinfo32检测SATA端口的方法&#xff1a;1、直接下载…

mfc try catch 捕获并显示_你的异常捕获够优雅不?求你别只会try{...} catch{...}了

文章来源 | cnblogs.com/jurendage/p/11255197.html作者 | 巨人大哥软件开发过程中&#xff0c;不可避免的是需要处理各种异常&#xff0c;就我自己来说&#xff0c;至少有一半以上的时间都是在处理各种异常情况&#xff0c;所以代码中就会出现大量的try {...} catch {...} fin…

五年级计算机教材内容,五年级计算机教学计划

五年级计算机教学计划教育结构不断发生变革&#xff0c;现代教育和教学理论主张对教学计划的结构实行改革。下面是小编为您整理的关于五年级计算机教学计划的相关资料&#xff0c;欢迎阅读&#xff01;五年级计算机教学计划 范例1一、教材分析选用的教材是&#xff0c;浙江摄影…

linux添加用户命令_为Linux的cp和mv命令添加进度条

cp和mv可能是大家日常中使用最多的Linux命令之一。但是有一个突出的问题是这两个命令都不会有任何提示信息&#xff0c;这在操作大文件时候只能干等。可能大家对此已经习以为常&#xff0c;但是其实上也有解决解决方法&#xff0c;本文我们就介绍一个Gnu Coreutils(cp和mv的源代…

unsigned long long 溢出 乘_Java整数相加溢出怎么办?Java8一步搞定

问题在之前刷题的时候遇见一个问题&#xff0c;需要解决int相加后怎么判断是否溢出&#xff0c;如果溢出就返回Integer.MAX_VALUE解决方案JDK8已经帮我们实现了Math下&#xff0c;不得不说这个方法是在StackOverflow找到了的&#xff0c;确实比国内一些论坛好多了~加法public s…

setstate是同步还是异步_谈谈 IO模型:同步、异步、阻塞、非阻塞

同步/异步、阻塞/非阻塞 说的是一回事儿吗&#xff1f;同步/异步、阻塞/非阻塞 你能通俗易懂的讲清楚吗&#xff1f;Java 中的 BIO、NIO、AIO 你了解吗&#xff1f;Socket 编程你还会吗&#xff1f;Linux 操作系统的 IO 模型你能讲讲吗&#xff1f;01. 生活中的同步/异步、阻塞…

md5会重复吗_如何优雅地处理重复请求(并发请求)

点击上方“服务端思维”&#xff0c;选择“设为星标”回复”669“获取独家整理的精选资料集回复”加群“加入全国服务端高端社群「后端圈」利用唯一请求编号去重你可能会想到的是&#xff0c;只要请求有唯一的请求编号&#xff0c;那么就能借用Redis做这个去重——只要这个唯一…

计算机二级excel数据有效性,原来Excel数据有效性还可以这样做——制作二级下拉菜单...

很多时候&#xff0c;在进行设置数据有效性时&#xff0c;我们希望可以根据前一单元格的内容&#xff0c;使用动态的数据选项。如下图为一个员工信息表&#xff0c;现希望在F列制作下拉列表&#xff0c;下拉列表的内容根据E列输入的省份变化而变化&#xff0c;如在E2单元格中输…

win7系统安装信息服务器不可用怎么办,Win7系统下iis服务器应用程序不可用怎么办?...

Win7系统用户在使用电脑系统时都有自带可以方便用户们搭建网站的iis服务器。不过也有Win7系统用户反映在电脑系统里添加或删除组件时iis服务器无法添加&#xff0c;还弹跳出了应用程序不可用的提示窗口&#xff0c;这使用户非常苦恼&#xff0c;那么Win7系统下iis服务器应用程序…

++ 多核cpu 并行_一文读懂什么是多核并行计算(三)

导读&#xff1a;面向应用工程师的商业软件咨询、自研软件定制开发服务的仿真公众号&#xff0c;点击关注进入菜单&#xff0c;查看更多精彩内容。(三)如何实现多核并行计算呢&#xff1f;了解了多核、多Machine、多Rack后&#xff0c;我可以看一下软件(程序)是如何对这些资源进…

服务器放行6in4协议,最简单的接入IPv6网络的方法 – 6in4隧道

很多大学的校园网启用了IPv6&#xff0c;并且建设了很多IPv6专享的资源。毕业离校&#xff0c;由于现在的网络运营商绝大部分尚未支持IPv6&#xff0c;所以那些资源也就离我们远去了。机缘巧合之下&#xff0c;我知道了&#xff0c;原来我们可以这样接入IPv6网络。目前接入IPv6…

梦幻群侠传5帮派修炼_梦幻西游:2020年十大更新回顾 法连不秒空和连续战斗修复...

今年梦幻西游有过很多重大的维护更新&#xff0c;其中不少更新都对玩家产生中重大的影响&#xff0c;比如说法术连击第二下不会秒空气&#xff0c;以及副本的迭代等等&#xff0c;今天就来盘点下2020年梦幻西游的十大更新!一、各类副本优化迭代今年优化了多个副本&#xff0c;如…

前端图片上坐标连线_前端图形学(十三)——弹跳运动的深入之傲娇的小球

欢迎来到【畅哥聊技术】前端图形学相关技术文章&#xff0c;更多精彩内容持续更新中,敬请关注。前面我们说到了小球的弹跳运动&#xff0c;通过一个方向的加速度和摩擦力去影响小球的动画&#xff0c;其目标点也是一个固定不变的&#xff0c;似乎有些单调。那么我们今天继续小球…

服务器微信了早上好,微信早晨好问候语句动态图片 早上好发给朋友的微信早安问候语简短...

原标题&#xff1a;微信早晨好问候语句动态图片 早上好发给朋友的微信早安问候语简短嘀嘀嘀嘀&#xff0c;我的短信到啦。用关心方式&#xff0c;要你多注意休息&#xff1b;用体贴方式&#xff0c;要你轻松而快乐&#xff1b;用祝福方式&#xff0c;要你一切都过的好&#xff…

c语言调用createthread线程的头文件_易语言API多线程总汇

【thread】 即&#xff0c;线程&#xff0c;是进程中某一顺序的控制流&#xff0c;在单个程序中同时运行多个线程完成不同工作&#xff0c;称为多线程。易语言多线程理解&#xff1a;进程是一个可执行程序&#xff0c;由私有虚拟地址空间、代码、数据和其它操作系统资源组成&am…

oracle varchar默认长度_面试官:如何精确计算mysql数据库索引长度?

概述我们知道MySQL Innodb 对于索引长度的限制为 767 字节&#xff0c;并且UTF8mb4字符集是4字节字符集&#xff0c;则 767字节 / 4字节每字符 191字符(默认索引最大长度)&#xff0c;所以在varchar(255)或char(255) 类型字段上创建索引会失败&#xff0c;提示最大索引长度为7…

android things 系统镜像文件_开始菜单搬家!Win 10X 系统 UI 全部重做,明年初就能用上...

不知道老伙计们还记不记得&#xff0c;小淙曾经报道过三次&#xff0c;关于微软新系统 Windows 10X 的消息。当时很多老伙计感觉太遥远&#xff0c;或者觉得它难以激起波澜。但现在看来微软布局已久&#xff0c;是铁了心要搞新系统了。因为 Windows 10X 系统已经准备好交付&…

通达信公式大全_通达信MACD金叉的选股公式大全

公式来源于网络&#xff0c;我只是用其中一个&#xff0c;一起复制来了&#xff0c;有需要的自取吧。1、0轴上方第一次金叉选股公式&#xff1a;DIFF:EMA(CLOSE,12) - EMA(CLOSE,26);DEA : EMA(DIFF,9);MACD : 2*(DIFF-DEA);xg:cross(diff,dea) and dea>-1.0 and dea<0.5…

mysql 时间差_后端从mysql取值返回0时区时间数据的问题

近日搞一个B/S项目&#xff0c;前端页面时间字段总是显示格林威冶时间&#xff0c;也就是0时区的时间&#xff0c;比北京时间差了8个小时。打开后台的数据库&#xff0c;在workbench中查询&#xff0c;结果显示的时间格式正常&#xff0c;为当前北京时间。该时间字段是在往数据…