日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時(shí)間:2025/3/11 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 解释型语言和编译型语言的区别_从泛型的使用情况看出你对语言的理解程度(2)... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上篇我們提到:Java中的泛型是不可變的,可以通過<? extends E>實(shí)現(xiàn)了泛型的協(xié)變,<? super E>實(shí)現(xiàn)泛型的逆變。從泛型的使用情況看出你對語言的理解程度(1)

今天我們來講講泛型單例工廠,在之前的推文中也有推送過單例模式的實(shí)現(xiàn),但是不是用泛型實(shí)現(xiàn)的,這次我們先講一個(gè)泛型單例的例子,然后再講泛型單例工廠會更好理解一些。

首先定義一個(gè)泛型接口,里面包含一個(gè)apply方法:

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

然后我們需要一種String類型的數(shù)據(jù)進(jìn)行apply操作的單例對象。按慣性思維,我們會這么實(shí)現(xiàn)。

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;} }

在工程需求復(fù)雜的情況下,這種模式?jīng)]有考慮到代碼的擴(kuò)展性,當(dāng)未來需要對Integer對象數(shù)據(jù)進(jìn)行apply操作呢?再寫一個(gè)類嗎?這明顯是過于麻煩了。這時(shí)候就需要再結(jié)合工廠的設(shè)計(jì)模式了。

泛型單例工廠

在工廠中,會產(chǎn)生不同參數(shù)類型的Money對象,在結(jié)合static的特性,實(shí)現(xiàn)復(fù)用生成的Money對象。

public class MoneyImp {//Money是類似函數(shù)式接口實(shí)現(xiàn)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接口其實(shí)是仿照J(rèn)ava8中的Function函數(shù)式接口定義的,或者說是仿照Function接口的子類接口:UnaryOperator。關(guān)于Function函數(shù)式接口可以看今天的另一篇推文介紹。簡單的說,Function就是實(shí)現(xiàn)了這樣的一個(gè)公式:y=f(x),而UnaryOperator實(shí)現(xiàn)的是:x=f(x)。

也就是說IDENTITY_FUNCTION 其實(shí)實(shí)現(xiàn)的是x=String.valueOf(f(x))的功能。在這里我們將傳進(jìn)來的x獲取其hashCode,然后轉(zhuǎn)換成字符串形式返回回去。同時(shí)由于IDENTITY_FUNCTION 是一個(gè)Money<Object> 。用Object接收返回的String(f(x))所以是合理的(父類引用指向子類對象)所以,還是可以把IDENTITY_FUNCTION 看作是x=f(x)。

arg -> String.valueOf(arg.hashCode());這個(gè)函數(shù)由于hashCode() 屬于Object,所以任何類調(diào)用都不會報(bào)錯(cuò)。否則很容易報(bào)錯(cuò),這里要多注意。

如果沒有g(shù)etMoneyInstance() 方法,而是直接把IDENTITY_FUNCTION 賦值給paperMoney 即:

Money<String> paperMoney = IDENTITY_FUNCTION();

則會報(bào)編譯錯(cuò)誤:

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)

這個(gè)很明顯,因?yàn)榉盒褪遣豢梢詤f(xié)變的。所以我們需要一個(gè)靜態(tài)工廠方法:getMoneyInstance()。

所有重點(diǎn)來了:

getMoneyInstance() 方法的作用,則是作為一個(gè)靜態(tài)工廠方法用于獲取我們編寫的IDENTITY_FUNCTION 函數(shù)。代碼中由于對IDENTITY_FUNCTION 進(jìn)行了強(qiáng)制類型轉(zhuǎn)換return (Money<T>) IDENTITY_FUNCTION; 所以需要添加unchecked 轉(zhuǎn)換警告,因?yàn)榫幾g器并不知道Money<Object> 的每個(gè)都是Money<T> ,但是因?yàn)镮DENTITY_FUNCTION 表示的是x=f(x),所以我們可以確定返回的就是Money<T> 。這是類型安全的。一旦我們這樣做了,代碼編譯就不會出現(xiàn)錯(cuò)誤或警告。

于是,我們就可通過getMoneyInstance() 獲取到處理特定類型的Money 如:paperMoney 、coinMoney 和 objMoney 。也就實(shí)現(xiàn)了一個(gè)泛型的單例工廠。

上面代碼的輸出結(jié)果如下:

110182 3143346 114717 1 2 3 103054

《Effective Java》中對泛型單例工廠的描述如下:

有時(shí),你需要創(chuàng)建一個(gè)對象,該對象是不可變的,但適用于許多不同類型。因?yàn)榉盒褪怯刹脸龑?shí)現(xiàn)的,所以你可以為所有需要的類型參數(shù)化使用單個(gè)對象,但是你需要編寫一個(gè)靜態(tài)工廠方法,為每個(gè)請求的類型參數(shù)化重復(fù)分配對象。這種模式稱為泛型單例工廠,可用于函數(shù)對象,如 Collections.reverseOrder,偶爾也用于集合,如 Collections.emptySet。

最后再提一點(diǎn)關(guān)于擦除的,由于Java泛型是由擦除實(shí)現(xiàn)的,所以,其實(shí)上面的代碼在便后后類似于這樣:

public class MoneyImp {//Money是類似函數(shù)式接口實(shí)現(xiàn)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));} }

運(yùn)行結(jié)果和前面的一樣且不報(bào)錯(cuò)。那我們?yōu)槭裁催€這么費(fèi)勁用個(gè)泛型搞得云里霧里的呢?因?yàn)槲覀兿胍@取到專門處理某一種類型的Money:paperMoney 、coinMoney 、objMoney 。如果不適用泛型,用上面的代碼,那么這三個(gè)paperMoney 、coinMoney 、objMoney 其實(shí)是沒有限制的,沒辦法裝門處理某一種特定類型啦。

好了,就到這里,不理解的朋友可以留言一起討論哦~

關(guān)注公眾號獲取更多內(nèi)容,有問題也可在公眾號提問哦

強(qiáng)哥叨逼叨

叨逼叨編程、互聯(lián)網(wǎng)的見解和新鮮事

總結(jié)

以上是生活随笔為你收集整理的解释型语言和编译型语言的区别_从泛型的使用情况看出你对语言的理解程度(2)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。