中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

做網(wǎng)站優(yōu)化選阿里巴巴還是百度網(wǎng)絡(luò)營銷推廣策劃

做網(wǎng)站優(yōu)化選阿里巴巴還是百度,網(wǎng)絡(luò)營銷推廣策劃,出入成都最新規(guī)定今天,第一營銷網(wǎng)作為一個 Java 程序員&#xff0c;用到泛型最多的&#xff0c;我估計應(yīng)該就是這一行代碼&#xff1a; List<String> list new ArrayList<>();這也是所有 Java 程序員的泛型之路開始的地方啊。 不過本文講泛型&#xff0c;先不從這里開始講&#xff0c;而是再往前…

作為一個 Java 程序員,用到泛型最多的,我估計應(yīng)該就是這一行代碼:

List<String> list = new ArrayList<>();

這也是所有 Java 程序員的泛型之路開始的地方啊。

不過本文講泛型,先不從這里開始講,而是再往前看一下,看一看沒有泛型的時候,Java 代碼是怎么寫的,然后我們才會知道為什么要加入泛型,泛型代碼該怎么寫。

這里插播一下我的微信公眾號,希望大家能夠多多關(guān)注,我會不定期更新優(yōu)秀的技術(shù)文章:

接下來,開始我們的正文。

為什么要設(shè)計泛型

提高代碼重用性

沒有泛型之前,我們寫一個兩數(shù)相加的函數(shù):

public static int add(int a, int b) {return a + b;
}

看似沒問題,對吧。不過這個時候我們想計算 float 類型的加法,那這個函數(shù)就不行了,因為他只能計算 int 值。此時就只能再加入一個相同的函數(shù)了:

public static float add(float a, float b) {return a + b;
}

現(xiàn)在我們有兩個方法能夠計算 int 和 float 類型的加法。那現(xiàn)在如果要計算 String 類型的加法呢,這兩個方法就又不夠用了。面對這樣的需求,在沒有泛型的支持下,我們只能不斷地增加邏輯基本相同的方法,代碼重用性極低。
這就是泛型要解決的第一個問題:提高代碼重用性。
那在泛型的加持下,我們?nèi)绾尉帉戇@個函數(shù)呢?

public static <T extends Number> double add(T a, T b) {return a.doubleValue() + b.doubleValue();
}

這個方法使用了泛型,它能夠處理任何類型的數(shù)字相加,不需要針對每個類型編寫各自的加法方法。這就大大提高了代碼的重用性,有了這個方法,那些固定類型的方法就都可以刪了。
特別是一些邏輯相同的代碼,使用泛型不僅能夠提高代碼重用性,還能夠提高可讀性。比如說下面這段代碼,真是的是非常好用:

public static <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}
}

泛型的這個特性雖然很牛了,但是這還不是 Java 要設(shè)計泛型的全部原因。因為泛型還有一個作用,那就是保證類型安全。

保證類型安全

在說泛型的這個作用之前,先問大家一個問題,咱們常用的集合 ArrayList 是 Java 哪個版本加入的呢?泛型又是 Java 哪個版本加入的呢?

答案:ArrayList 是 Java 1.2 版本加入的,而泛型是 Java 1.5 加入的。

也就是說,有一段時時間,ArrayList 不是大家普遍認(rèn)識的帶泛型的 ArrayList<T> 這種形式,而是一個只能存放 Object 的列表。

在那一段泛型之光沒有照耀到 Java 的日子里,保證類型安全成為了 Java 程序員在使用集合時不得不考慮的事情,考慮下面這一段代碼:

ArrayList list = new ArrayList();
list.add("123");
// do some work......
Integer num = (Integer) list.get(0);

這段代碼沒有使用泛型來使用 ArrayList,我們加入了字符串 "123",但是在使用時,我們假定程序員忘記了加入的類型,他只記得好像應(yīng)該是數(shù)字,于是在獲取時就直接使用了 Integer 類強(qiáng)轉(zhuǎn)。

這樣的代碼是能通過編譯的,但是在運(yùn)行的時候,會崩潰:

 Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

這是一個典型的未使用泛型,而導(dǎo)致的類型安全無法保證,引發(fā)的崩潰。讓程序員去保證類型安全,本身是不靠譜的做法,特別是在這種都是 Object 對象的列表中,鬼都不會知道存著的是個什么鬼。

這個時候就需要泛型出場了,泛型能夠在編譯時保證類型安全。例如上面的代碼,我們加入泛型:

ArrayList<String> list = new ArrayList<>();
list.add("123");
Integer num = (Integer) list.get(0);

首先,ArrayList 加入泛型后,我們就知道這個列表是只能存入 String 類型的,也就不會將其轉(zhuǎn)換為 Integer。那如果我非要轉(zhuǎn)換呢,javac 編譯器就會報錯:

錯誤: 不兼容的類型: String無法轉(zhuǎn)換為IntegerInteger num = (Integer) list.get(0);

這樣類型安全就可以在編譯時得到保證,不會出現(xiàn)在運(yùn)行時的崩潰。

例子的代碼很簡單,大家可能看不到這一點對于軟件開發(fā)有多重要,在大型復(fù)雜的項目中,這種類型安全的保證,是能減少很多運(yùn)行時的崩潰的。特別是,一般像這種類型不一致的崩潰很多都是偶現(xiàn)的,偶現(xiàn)的 BUG 是最惡心的,因此使用泛型保證類型安全是十分必要的。

消除強(qiáng)制類型轉(zhuǎn)換

泛型的這個作用其實就是上面保證類型安全這一點帶來的。沒有用泛型時,需要我們使用強(qiáng)制類型轉(zhuǎn)化,但是加入泛型后,編譯器已經(jīng)能夠知道我們存入的是什么類型,因此也就不需要我們進(jìn)行強(qiáng)制類型轉(zhuǎn)換了。

既然泛型有那么大的作用,那我們就趕緊把泛型用起來吧。

使用泛型

這一節(jié),我們來看看如何使用系統(tǒng)提供的泛型類,以及其中需要注意的事項。

最常用到泛型的地方便是集合了,使用這些泛型集合類時,只需要把具體泛型參數(shù) <T> 替換為需要的類型即可,例如 ArrayList<String>、ArrayList<Number>、 Map<String, Integer> 等。

如果在使用泛型類時不指定類型參數(shù),編譯器會給出警告,且只能將 <T> 視為 Object 類型。這個時候就需要程序員自己去保證類型安全了,因此強(qiáng)烈不建議這么做,因為這樣容易將類型轉(zhuǎn)換異常帶到運(yùn)行時中去。

使用泛型基本就需要注意以上兩點,下面介紹一下在使用泛型時的注意事項,這也是大家很少關(guān)注到的向上轉(zhuǎn)型的問題。

在 Java 中,ArrayList<T> 是實現(xiàn)了 List<T> 接口,也就是說它可以向上轉(zhuǎn)型為 List<T>

public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable

那么問題就來了,當(dāng)泛型參數(shù)不同時,還能向上轉(zhuǎn)型么,說具體一點,ArrayList<String> 能轉(zhuǎn)型為 List<Number> 么?

答案是不行的:

ArrayList List = new ArrayList<String>();    //Raw use of parameterized class 'ArrayList'
List<Integer> list = new ArrayList<String>();    //直接報錯

為什么 Java 不允許這么轉(zhuǎn)型呢?因為運(yùn)行轉(zhuǎn)型的話,那么對于一個 ArrayList<String> 的容器,我將其轉(zhuǎn)型為 ArrayList<Integer> 就可以往里面加入 Integer 對象了,這明顯會造成 ClassCastException。泛型的存在用于限定類型的,這么一搞,泛型就失去了其作用。

這里,大家可以簡單理解為,當(dāng)泛型參數(shù)不一樣時,兩個類就沒有太大關(guān)系了。例如 ArrayList<Integer>List<Number> 兩者完全沒有繼承關(guān)系。

編寫泛型

知道怎么使用系統(tǒng)的泛型之后,我們現(xiàn)在就來看看如何編寫自己的泛型類。

泛型作為對類型進(jìn)行限制的一種方式,我們編寫泛型代碼,也就是對使用我們代碼的人進(jìn)行一種限制。在這種情況下,我們是作為其他程序員的底層,向上提供某種框架代碼,讓其他程序員能夠在我們設(shè)定的框架中更容易地編寫代碼實現(xiàn)功能。這有點類似于庫的開發(fā)者,或是框架開發(fā)者,作為這種角色,寫好泛型代碼就更顯得尤為重要了。畢竟,你也不想讓別人說,這代碼寫得就跟一坨屎一樣吧。

編寫泛型類

編寫泛型類,是比普通類要復(fù)雜的。這里我們就用 Pair<F, S> 這個類作為目標(biāo),一步一步編寫出一個合格的泛型類。Pair 類是 Android 開發(fā)中一個簡單的使用工具類,用于存儲一對相關(guān)聯(lián)的對象。

我們的第一版 Pair 只能使用沒有使用泛型:

public class Pair {public final String first;public final String second;
}

那這肯定是不行的,因為這個 Pair 只能存放 String 類型的 first 和 second,那了能夠存放所有類型,我們就使用泛型 <T>

public class Pair<T> {public final T first;public final T second;
}

我們把 firstsecondT 來修飾,表示其這兩個成員變量是 T 類型的。而這個 T 類型,Java 是不知道的,我們必須聲明告訴 Java 這是一個類型,因此類名從 Pair 變成了 Pair<T>,后面的 <T> 就是我們的泛型類型聲明。

上面的代碼看上去沒問題,但是這個 Pair<T> 只能存放的 firstsecond 必須是相同的類型 T,那不同類型的怎么辦呢?這時候我們再加一個泛型不就行了:

public class Pair<F, S> {public final F first;public final S second;
}

在加入兩個泛型之后,firstsecond 的類型對應(yīng)不同的泛型,這樣就可以表示不同的類型了,注意 F、S 這兩個不同的泛型都需要在類上進(jìn)行聲明。

我們在為 Pair<F, S> 添加個構(gòu)造方法:

public class Pair<F, S> {public final F first;public final S second;public Pair(F first, S second) {this.first = first;this.second = second;}
}

這算是一個簡單的泛型類,那接下來,我們再為它編寫一個泛型方法。

編寫泛型方法

此處的泛型方法是指靜態(tài)方法,而不是成員方法。這兩種方法在使用泛型時是有一些區(qū)別的,其中最重要的一點就是,靜態(tài)方法是不能使用類上聲明的泛型類型,必須得自己聲明泛型類型。例如,下面的代碼將編譯錯誤:

public static class Pair<F, S> {public final F first;public final S second;//編譯錯誤,F、S 類型不能在 static 方法上使用public static Pair<F, S> create(F a, S b) {return new Pair<F, S>(a, b);}
}

可以想一想,為什么靜態(tài)方法不能使用類上已經(jīng)聲明的泛型類型呢?

在回答這個問題之前,我們可以先想一下,類上的泛型類型,是在什么時候確定下來的呢?是在類創(chuàng)建的時候,我們在 new 的時候是需要提供具體類型的,這個時候泛型就被具體化為某個特定類型。不同的對象可能被創(chuàng)建為不同的類型,而靜態(tài)方法只跟類相關(guān),跟具體對象無關(guān),而這些泛型又是跟具體對象相關(guān)的。所以靜態(tài)對象不能使用類上聲明的泛型也就變得合理了。

那要想使靜態(tài)方法使用泛型,那就必須這個靜態(tài)方法自己聲明泛型:

public static <F, S> Pair <F, S> create(F a, S b) {return new Pair<F, S>(a, b);
}

這個靜態(tài)方法在函數(shù)名前使用 <F, S> 來聲明了兩個泛型,那么后續(xù)這兩個泛型就可以在這個函數(shù)中使用了。此時注意,這里的 F、S 雖然與 Pair 上的 F、S 泛型看似相同,實際上是沒有任何關(guān)系的。所以為了避免產(chǎn)生誤會,一般都會使用不同的泛型名,例如將這個方法的 <F, S> 變成 <A, B>

public static class Pair<F, S> {public final F first;public final S second;public static <A, B> Pair <A, B> create(A a, B b) {return new Pair<A, B>(a, b);}
}

這樣才能夠清楚地將靜態(tài)方法的泛型類型和實例類型的泛型類型區(qū)分開。

在使用時,我們可以使用如下代碼創(chuàng)建一個 Pair<F, S> 實例:

Pair<String, Integer> pair = Pair.create("123", 123);

這里總結(jié)一下編寫泛型需要注意的幾點:

  • 編寫泛型時,需要定義泛型類型 <T>
  • 靜態(tài)方法不能引用類上的泛型類型 <T>,必須定義自己方法特有的泛型類型;
  • 泛型可以同時定義多個,例如 <F, S>、<F、S、T>

在這里我們需要注意泛型的一個限制,那就是不能使用泛型類型直接創(chuàng)建對象。這一點也好理解,T 是什么類型只有在使用時,指定了泛型的具體類型才能確定。T 類型是一個抽象的類型,它是無法直接 new 出來的,就像你無法直接 new 一個 interface 一樣。例如下面的代碼是錯誤的:

public static class Pair<F, S> {public final F first;public final S second;public Pair(F first, S second) {this.first = new F();        //錯誤this.second = new S();       //錯誤}
}

這里使用 F 類型的默認(rèn)構(gòu)造,設(shè)想一下假如這個類型被確定為一個沒有默認(rèn)構(gòu)造方法的類型呢。所以使用泛型類型創(chuàng)建對象是不行的。

Java 的泛型實現(xiàn)方式:類型擦除

上面的幾節(jié)介紹了泛型的好處,泛型的使用,那這一節(jié)我們就來看看 Java 是如何實現(xiàn)泛型技術(shù)的。

首先,泛型編程并非 Java 特有的,在其他語言 C++、C# 上都有類似的技術(shù),只不過名稱不同而已,例如 C++ 上叫模版。在這些技術(shù)的加持下,程序員可以編寫與具體類型無關(guān)的代碼,只需要在使用時指定具體類型,從而提高代碼的復(fù)用性;并且在編譯時進(jìn)行類型檢查,減少運(yùn)行時錯誤。

Java 的泛型是通過類型擦除(Type Erasure)來實現(xiàn)的。也就是說在編譯時將泛型類型擦除,替換為其上限類型(通常為 Object),并在必要時插入類型轉(zhuǎn)換。這種機(jī)制在編譯時處理泛型類型,而在運(yùn)行時移除了所有的泛型信息,因此叫做類型擦除。

這也就意味著,Java 的泛型是由編譯器實現(xiàn)的,在編譯成 class 文件時類型信息已經(jīng)被擦除了,因此運(yùn)行時,Java 虛擬機(jī)是沒有任何泛型信息的。

例如上面我們編寫的 Pair 的這個類,在我們看來,它是這樣的,在源代碼階段,里面是包含泛型信息的:

public static class Pair<F, S> {public final F first;public final S second;public Pair(F first, S second) {this.first = first;this.second = second;}public static <A, B> Pair<A, B> create(A a, B b) {return new Pair<A, B>(a, b);}
}

那么在虛擬機(jī)的視角,它是這樣的:

public class Pair {private Object first;private Object last;public Pair(Object first, Object last) {this.first = first;this.last = last;}
}

從這里就能看到,這個 Pair 在運(yùn)行時已經(jīng)沒有泛型信息了,所有的泛型類型都被替換為了 Object

那么既然我們定義的泛型類型最終都變成了 Object,那我們就知道了 Java 泛型的一個局限:泛型類型 <T> 不能是基本類型。
因為像 int、float 這些基本類型不是 Object 的子類,所以我們必須使用包裝類:

Pair<float, int> pair = Pair.create(3.15, 123);    //編譯錯誤
Pair<Float, Integer> pair = Pair.create(3.15F, 123);    //編譯通過

盡管 Java 的泛型在編譯時通過類型擦除機(jī)制移除了泛型類型信息,但 Java 編譯器會在 class 文件中保留一些泛型信息,以便工具和開發(fā)人員能夠利用這些信息進(jìn)行反射和調(diào)試。所以如果大家把這個類編譯為 class 文件之后,再查看它的反編譯的內(nèi)容,會發(fā)現(xiàn)它是有一些泛型信息的。但這并不意味著 JVM 在運(yùn)行時會攜帶這些類型信息,既然是類型擦除,也就是說泛型類型參數(shù)被擦除并替換為其邊界類型,如果沒有指定邊界,則默認(rèn)為 Object。

這里又引入了邊界類型這個概念,在下一篇文章中,我們就來詳細(xì)聊聊這個邊界類型,這也是泛型中比較重要和難的點。

http://www.risenshineclean.com/news/47914.html

相關(guān)文章:

  • 網(wǎng)站建設(shè)經(jīng)費預(yù)算seo廣告平臺
  • 跨境網(wǎng)絡(luò)專線多少錢一年網(wǎng)站seo方案案例
  • 永清縣建設(shè)局網(wǎng)站發(fā)稿軟文公司
  • 創(chuàng)業(yè)做網(wǎng)站 優(yōu)幫云品牌推廣方案怎么寫
  • 牌具網(wǎng)站廣告怎么做開一個免費網(wǎng)站
  • 網(wǎng)站虛擬主持百度域名收錄
  • 金融投資網(wǎng)站 php源碼aso推廣
  • 做網(wǎng)站的公司網(wǎng)站seo診斷分析和優(yōu)化方案
  • 國內(nèi)最新疫情福州seo服務(wù)
  • 什么網(wǎng)站專門做二手物品營銷公司網(wǎng)站
  • 交友網(wǎng)站開發(fā)的意義網(wǎng)站推廣的策略
  • 網(wǎng)絡(luò)營銷方式有電腦優(yōu)化軟件排行榜
  • 免費建設(shè)門戶網(wǎng)站巨量引擎廣告投放平臺官網(wǎng)
  • 天津市網(wǎng)站建設(shè)+網(wǎng)頁制作seo網(wǎng)站排名軟件
  • 愛戰(zhàn)網(wǎng)關(guān)鍵詞挖掘查詢工具成都優(yōu)化網(wǎng)站哪家公司好
  • 洛陽網(wǎng)站推廣方式今日軍事頭條
  • 濟(jì)南學(xué)習(xí)網(wǎng)站制作怎樣宣傳網(wǎng)站
  • 產(chǎn)品推廣軟文200字汕頭seo關(guān)鍵詞排名
  • 網(wǎng)站后臺無法審核淘寶seo搜索引擎原理
  • 適合做外鏈的網(wǎng)站百度競價排名公司
  • 杭州建設(shè)市場監(jiān)管平臺seo長尾關(guān)鍵詞優(yōu)化
  • .net 網(wǎng)站 iis 配置四川seo優(yōu)化
  • 臨西企業(yè)做網(wǎng)站百度官方客服電話
  • wordpress客服設(shè)置廣州關(guān)于進(jìn)一步優(yōu)化疫情防控措施
  • 南京網(wǎng)站制作設(shè)計公司鄭州好的seo外包公司
  • 如何利用網(wǎng)站做demo怎么讓百度搜出自己
  • 網(wǎng)站關(guān)鍵詞推廣方案免費淘寶關(guān)鍵詞工具
  • 桂林網(wǎng)站制作公司磁力搜索器下載
  • 設(shè)計師找素材的網(wǎng)站網(wǎng)站被禁用如何解決
  • 長沙企業(yè)網(wǎng)站建設(shè)企業(yè)百度關(guān)鍵詞怎么刷上去