JDK5.0新特性之:泛型

文/陳剛 2005-11-09?

一、前言

  泛型這個詞在現在的JAVA挺時髦,光從字面上你是無法知道它代表些什么東東的,所以我們還是不要從字面去理解,而是從一些實例去了解它吧。

二、泛型之前的日子

  JDK1.4之前是沒有泛型的概念的,所以我們才會有下面的代碼:

        List list = new ArrayList();
list.add("aaaa");
list.add("bbbb");
list.add("cccc");
        for (Iterator it = list.iterator(); it.hasNext();) {
String str = (String) it.next();
System.out.println(str);
}

  上面是一段很平常的代碼,在一個List集合加入一些字符串,然后再用一個遍歷循環把它打印出來。“String str = (String) it.next()”這一句我們可以看到List取出值都是Object,所以我們要得String型,還要做一個類型轉換,真是麻煩。更麻煩的是list.add(Object obj)的參數是Object類型,所以如果我們一不小心把list.add("cccc");寫成list.add(new Integer(76));程序在循環打印的類型轉換中就會出錯。

  問題:我們能不能讓add方法只認String型呢?
回答:可以!用JDK5.0的泛型。

三、泛型后的幸福生活

  JAVA有了泛型后,就象十年的老光棍討了老婆,那個好處自不待言。我們來看看上面的例子改成泛型的寫法是怎么樣的:

        List<String> list = new ArrayList<String>();
list.add("aaaa");
list.add("bbbb");
list.add("cccc");
        for (Iterator<String> it = list.iterator(); it.hasNext();) {
String str=it.next();
System.out.println(str);
}

  看到差別了嗎?泛型其實很簡單,就是在定義類型的后面加上"<類型>"這樣子的聲明就行了,它主要還有以下差別:

  • list.add方法只能接受String類型。list.add(new Integer(76))這樣的語句不需要運行程序,在編譯時就會檢查通不過。
  • it.next()的返回值不再是Object,而變成了String

  當然我們其實在循環部份也可以象下面這么寫,是不是簡潔了很多呢 :-)

        List<String> list = new ArrayList<String>();
list.add("aaaa");
list.add("bbbb");
list.add("cccc");
        for (String str : list) {
System.out.println(str);
}

  當然需要說明的是,List不僅可以List<String>,也可以是List<Integer>等等其他任何類型。

四、更深入了解泛型

(1)層層推進的泛型聲明

  “List<List> list;”表示什么呢?就是只接收List型的參數,比如:

??????? List<List> list = new ArrayList<List>();
list.add(new ArrayList());
list.add(new Vector());
list.add(new LinkedList());

  這里要注意List是接口,ArrayList、Vector、LinkedList都是這一接口下的實現類。下面這個有點怪異了,“List<List<String>> list;”表示它只接受List型的參數,而且這種List型的參數又是只是只接受String型,有點層層推進的味道在里面了。

??????? List<List<String>> list = new ArrayList<List<String>>();
list.add(new ArrayList<String>());
list.add(new Vector<String>());
list.add(new LinkedList<String>());

(2)使用泛型上限通通配符:extends

  這里要著重強調一點:變量的泛型聲明和方法的參數的泛型聲明有很大差別。

  變量聲明成某類型,同時也可以接受它的子類。比如說Integer、Long、Float都是抽象類Number的子類,所以下面的代碼一點問題也沒有:

??????? List<Number> list = new ArrayList<Number>();
list.add(new Integer(1));
list.add(new Long(1));
list.add(new Float(1.2));

  但如果換成方法參數的泛型聲明則要嚴格得多了:子類也是不行的。比如下面的代碼就是錯誤的,因為printList參數只接受Number值的List,就是是Number子類的Integer值的List也不行。

??? public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(new Integer(2));
printList(list);
}

private static void printList(List<Number> list){
for (Number num : list) {
System.out.println(num);
}
}

 上面代碼修改的方法有兩個,如下

修改方法一:改變量的泛型聲明
將 List<Integer> list = new ArrayList<Integer>();
改為 List<Number> list = new ArrayList<Number>();

修改方法二:用界限通配符改方法參數的泛型聲明
將 printList(List<Number> list)
改為 printList(List<? extends Number> list)
說明:extends 的含義就是表示參數可以接受Number型的子類。

(3)使用泛型下限通通配符:super

??  在上限就有下限,下限行就是super,用法和extends一樣,含義則和extends相反。比如printList(List<? super Integer> list)表示參數可以接受Integer型及Integer型的超類,即Number了,當然也包括Object這個頂級類。

(4)配置符:?

  ?表示可以接受任何類型,不過我覺得它用得不多,因為printList(List<?> list)和printList(List list)的作用是一樣的。

五、創建一個支持泛型的類

(1)創建一個泛型的類

public class Point<T> {
T x;
T y;
??? public T getX() {
return x;
}
??? public T getY() {
return y;
}
??? public void setX(T x) {
this.x = x;
}
??? public void setY(T y) {
this.y = y;
}
}

  使用這個類的代碼如下:

??????? Point<Integer> p = new Point<Integer>();
p.setX(new Integer(1));
p.setY(new Integer(2));

Point<String> b = new Point<String>();
b.setX("1");
b.setY("2");

  說明:在Point<T>的定義中,T并非關鍵字,你也可以這樣定義Point<ABC>,當然一般還是寫T吧,簡單也規范。

(2)泛型類的繼承與實現

  java.util.Comparator類是JDK里用來排序的,其源代碼如下:

package java.util;
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}

?? 一個實現此接口的類如下:

??? public class MyComparator<T> implements Comparator<ObjectInstance> {
public int compare(ObjectInstance o1, ObjectInstance o2) {
String s1 = o1.getObjectName().getCanonicalName();
String s2 = o2.getObjectName().getCanonicalName();
return s1.compareToIgnoreCase(s2);
}
}

  說明:ObjectInstance可能大家還太明白,這是我實際項目中的一段代碼(關于JMX的),ObjectInstance全稱javax.management.ObjectInstance。MyComparator的使用代碼如下:

Set set = ......(省略)
List<ObjectInstance> mbeans = new ArrayList<ObjectInstance>(set);
Collections.sort(mbeans, new MyComparator<ObjectInstance>());

六、最后的感言

  JAVA有了泛型就象老光棍討了老婆,好處大大的,但和女人一樣麻煩也跟著來了:它的嚴格類型檢查,使隱藏的BUG更少。有些地方確實也使代碼簡潔了,有些地方卻會使得代碼更復雜。所以運用之妙在于是否用得適當,盡量把泛型往簡單里用,別越搞越復雜了。?

參考資料

J2SE 5.0中的泛型 http://www.matrix.org.cn/resource/article/43/43634_java_generics.html

作者簡介

陳剛,廣西桂林人,著作有《Eclipse從入門到精通》
您可以通過其博客了解更多信息和文章:http://www.ChenGang.com.cn

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/256095.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/256095.shtml
英文地址,請注明出處:http://en.pswp.cn/news/256095.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

QT5.14.2基于PCL1.11.1顯示點云(基于Windows VS2019開發環境)

文章目錄一、安裝1.1 PCL安裝1.2 QT安裝1.3 VTK編譯二、程序配置1. 基于mscv創建QT的程序2. 配置QT工程文件和依賴項3. 編寫點云顯示的小程序總結一、安裝 1.1 PCL安裝 PCL1.11.1庫的安裝網上教程很多&#xff0c;推薦一個很好的教程&#xff1a; Win10 系統下 VisualStudio2…

Spring學習筆記—最小化Spring XML配置

自動裝配(autowiring)有助于減少甚至消除配置<property>元素和<constructor-arg>元素&#xff0c;讓Spring自動識別如何裝配Bean的依賴關系。 自動檢測(autodiscovery)比自動裝配更進了一步&#xff0c;讓Spring能夠自動識別哪些類需要被配置成Spring Bean&#xf…

【數據結構】——快速排序

目錄 一、代碼 二、復雜度&#xff1a;O(nlog(n)) 三、快速排序的劣勢 視頻參考鏈接&#xff1a;https://www.bilibili.com/video/BV1mp4y1D7UP?p17 一、代碼 思想&#xff1a;假設是對一個list進行排序 1、選取第一個元素作為p元素&#xff1b; 2、將p元素歸位&#xff0…

讀取數據庫信息構建視圖字段的備注信息,方便程序代碼生成

在很多情況下&#xff0c;我們開發都需要有一個快速的代碼生成工具用來提高開發效率&#xff0c;代碼生成工具很多信息都是讀取數據庫的表、視圖等元數據進行對象表信息的完善&#xff0c;有了這些信息&#xff0c;我們就可以在普通的實體類代碼里面添加屬性字段的中文注釋&…

Ubuntu DNS bind9 配置

下面的配置就是實現解析test.zp.com到不同的IP地址 安裝dns server軟件包$ apt-get install bind9 配置dns配置文件的路徑在/etc/bind路徑下面添加一個zone$ /etc/bind# vim /etc/bind/named.conf.local 添加下面&#xff0c;語法可以參照/etc/bind/zones.rfc1918中的語法添加&…

微博分享錯誤

昨天再做這塊的時候&#xff0c;不知怎么的點擊之后什么反應都沒有&#xff0c;程序也沒有崩&#xff0c;日志倒是輸出了這個錯誤 解決辦法&#xff1a;打開你寫分享的代碼跟API文檔對比一下創建文本、圖片或者網頁的時候是不是少寫了那個屬性&#xff0c;我這里是在創建網頁的…

C++總結筆記(十二)—— 智能指針

文章目錄前言一、智能指針是什么&#xff1f;二、示例總結前言 C對于內存管理的要求很高&#xff0c;如果不及時釋放對象內存&#xff0c;就可能會發生內存泄露或野指針等情況&#xff0c;鑒于這種情況&#xff0c;C11提出了智能指針的概念。 一、智能指針是什么&#xff1f;…

代碼生成工具之界面快速生成

界面開發&#xff0c;無論對于Web開發&#xff0c;還是Winform開發&#xff0c;都需要耗費一定的時間&#xff0c;特別對于一個數據庫字段比較多的界面&#xff0c;一般就需要在編輯界面上擺的更多的控件來做數據顯示&#xff0c;每次碰到這個&#xff0c;都有點頭痛&#xff0…

javascript - 封裝原生js實現ajax

1 /*2 * ajax方法3 */4 var Ajax function() {5 var that this;6 //創建異步請求對象方法7 that.createXHR function() {8 if(window.XMLHttpRequ…

QT對象樹、信號和槽機制

文章目錄一 、對象樹是什么&#xff1f;二、信號和槽的基本概念2.1 信號2.2 槽2.3 松散耦合2.4 特點三、示例總結一 、對象樹是什么&#xff1f; 對象樹是由父類和若干子類對象組成&#xff0c;而子類也可以由若干孫類。 QT中的對象樹是以QObject為起始父類來完成樹的構建的&a…

【數據結構】——歸并排序

目錄 一、代碼 二、隨筆 一、代碼 歸并排序的主要思路&#xff1a;將兩個有序的子列表歸并為一個有序的大列表 #歸并函數&#xff0c;假設li是由左右兩個有序的子列表組成,假設兩個子列表都是從小到大排好序的列表 def merge(li,low,mid,high)::param li: 由左右兩個有序的子列…

開發發布npm module包

開發發布npm module包 問題 在項目開發過程中&#xff0c;每當進入一個新的業務項目&#xff0c;從零開始搭建一套前端項目結構是一件讓人頭疼的事情&#xff0c;就要重新復制一個上一個項目的前端框架和組件代碼庫。其中很多功能的模塊組件都要重復拷貝&#xff0c;可以統一將…

如何使用ATS提高應用的安全性

App Transport Security&#xff0c;簡短的說就是ATS&#xff0c;是iOS9和OS X El Capitan的一個新特性。App Transport Security 的目標是提高Apple 操作系統的安全性以及在此操作系統上運行的任何應用的安全性。 基于HTTP傳輸數據的網絡請求都是明文。開啟App Transport Secu…

手機客戶端測試考慮的點

手機客戶端測試考慮點總結 版權聲明&#xff1a;本文為博主原創文章&#xff0c;未經博主允許不得轉載。 此文未本人工作中的總結&#xff0c;特此總結。 異常場景&#xff1a; 網絡異常&#xff0c;服務器異常&#xff0c;接口異常或參考參數篡改&#xff0c;斷電&#xff0c;…

NMS(非極大值抑制)算法詳解與示例

一、NMS是什么&#xff1f; NMS&#xff08;non maximum suppression&#xff09;即非極大值抑制&#xff0c;廣泛應用于傳統的特征提取和深度學習的目標檢測算法中。 NMS原理是通過篩選出局部極大值得到最優解。 在2維邊緣提取中體現在提取邊緣輪廓后將一些梯度方向變化率較小…

【數據結構】——冒泡排序、插入排序、選擇排序

# 冒泡排序&#xff0c;復雜度為O(n^2) def bubble_sorted(li:list)->list:for i in range(len(li)):# 第幾趟exchanged False# 這個是為了防止多余的遍歷&#xff0c;如果前面的元素已經是排序好的&#xff0c;那就不需要再進行比較了&#xff0c;減少運行時間for j in ra…

【轉載】ASP.NET應用程序與頁面生命周期

在本文中&#xff0c;我們將了解不同的事件&#xff0c;ASP.NET 應用程序的生命周期以瀏覽器向 Web 服務器&#xff08;對于 ASP.NET 應用程序&#xff0c;通常為 IIS&#xff09;發送請求為起點&#xff0c;直至將請求結果返回至瀏覽器結束。在這個過程中&#xff0c;首先我們…

基于PCL的ICP及其變種算法實現

文章目錄前言一、ICP算法基礎1.1 提取待匹配點對1.2 計算旋轉平移矩陣1.3 計算變換后的點和目標點之間的偏差二、ICP算法變種2.1 PLICP2.2 PointToPlane ICP2.3 NICP2.4 LM_ICP三、程序示例1. 傳統方法2. PointToPlane ICP總結前言 ICP&#xff08;Iterative Closest Point&am…

python 計算器

--coding:utf-8-- from Tkinter import * 創建橫條型框架 def frame(root, side): w Frame(root) w.pack(side side, expand YES, fill BOTH) return w 創建按鈕 def button(root, side, text, command None): w Button(root, text text, command command) w.pack(side…

最長公共子序列(LCS)

注意最長公共子串&#xff08;Longest CommonSubstring&#xff09;和最長公共子序列&#xff08;LongestCommon Subsequence, LCS&#xff09;的區別&#xff1a;子串&#xff08;Substring&#xff09;是串的一個連續的部分&#xff0c;子序列&#xff08;Subsequence&#x…