泛型方法

引言

泛型不僅可以應(yīng)用于整個(gè)類上,還可以在類中包含參數(shù)化的方法贮匕。而這個(gè)類所在的類可以是泛型類,也可以是非泛型類花枫。這就意味著刻盐,是否擁有泛型方法,與所在的類是否是泛型沒有關(guān)系乌昔。

泛型方法可以讓該方法獨(dú)立于整個(gè)類而變化隙疚。這就意味著,只要能做到磕道,那么就應(yīng)當(dāng)使用泛型方法。也就是說行冰,如果泛型方法可以取代整個(gè)類泛型化溺蕉,那么就應(yīng)該只使用泛型方法伶丐,因?yàn)樗梢允故虑楦拥厍宄靼住?br> 另外,對于一個(gè)static的方法而言疯特,無法訪問泛型類的類型參數(shù)哗魂,所以static要想使用泛型,則必須聲明為泛型方法漓雅。

定義

要定義泛型方法录别,只需將泛型參數(shù)列表置于返回值之前,如下邻吞。

public class GenericMethods {
    public <T> void f(T x) {
        System.out.println(x.getClass().getName());
    }

    public static void main(String[] args) {
        GenericMethods gm = new GenericMethods();
        gm.f("");
        gm.f(1);
        gm.f(1.0);
        gm.f(1.0f);
        gm.f('c');
        gm.f(gm);
    }
}
// Outputs
java.lang.String
java.lang.Integer
java.lang.Double
java.lang.Float
java.lang.Character
com.daidaijie.generices.method.GenericMethods

GenericMethods并不是參數(shù)化的组题,盡管這個(gè)類和其內(nèi)部的方法可以被同時(shí)參數(shù)化,但是在上面例子中抱冷,只有方法f()具有類型參數(shù)崔列,這是由該方法的返回類型前面的類型參數(shù)列表指明的。

注意旺遮,當(dāng)使用泛型類的時(shí)赵讯,必須在創(chuàng)建對象的時(shí)候指定類型參數(shù)的值,而使用泛型方法的時(shí)候耿眉,通常不必指明參數(shù)類型边翼,因?yàn)榫幾g器會(huì)為我們找出具體的類型。這稱為類型參數(shù)推斷鸣剪。因此讯私,我們可以像調(diào)用普通方法一樣調(diào)用f(),而且就像是f()被無限次的重載過西傀。它甚至可以接受GenericMethods作為其類型參數(shù)斤寇。
如果調(diào)用f()的時(shí)候傳入基本類型,那么將觸發(fā)自動(dòng)打包機(jī)制拥褂,將基本類型的值包裝對應(yīng)的對象娘锁。泛型方法和自動(dòng)打包機(jī)制減少了許多之前我們不得不編寫的代碼。

類型推斷的作用

在Java SE7之前饺鹃,如果要?jiǎng)?chuàng)建一個(gè)泛型對象莫秆,那么將必須寫非常啰嗦的代碼來實(shí)現(xiàn)。如果創(chuàng)建一個(gè)持有ListMap悔详,就要像下面那樣镊屎。

Map<Person,List<? extends Pet>> petPeople = new HashMap<Person,List<? extends Pet>>(); 

然而,在泛型方法中茄螃,類型參數(shù)推斷可以為我們簡化一部分的操作缝驳。我們可以編寫一個(gè)工具類,它包含各種各樣的static方法,專門用于創(chuàng)建各種常用的容器對象用狱。

public class New {
    public static <K, V> Map<K, V> mapOf() {
        return new HashMap<K, V>();
    }

    public static <T> List<T> listOf() {
        return new ArrayList<T>();
    }

    public static <T> LinkedList<T> linkListOf() {
        return new LinkedList<T>();
    }

    public static <T> Set<T> setOf() {
        return new HashSet<T>();
    }

    public static <T> Queue<T> queue() {
        return new LinkedList<T>();
    }

    public static void main(String[] args) {
        Map<String, List<String>> sls = New.mapOf();
        List<String> ls = New.listOf();
        LinkedList<String> lls = New.linkListOf();
        Set<String> ss = New.setOf();
        Queue<String> qs = New.queue();
    }
}

以上的類型推斷的一個(gè)使用运怖,盡管說這段代碼在Java SE7之前為創(chuàng)建類型少寫了很多代碼,但是如果有人需要閱讀以上的代碼夏伊,他必須去分析工具類New摇展,以及New所隱含的功能,這似乎導(dǎo)致了與不使用News的工作效率差不多溺忧。

類型推斷的限制

在Java SE8之前咏连,類型推斷也有一定限制,類型推斷只對賦值操作有效鲁森,將一個(gè)泛型方法調(diào)用的結(jié)果作為參數(shù)祟滴,傳遞給另一個(gè)方法,這時(shí)候編譯器并不會(huì)執(zhí)行類型判斷刀森。在這種情況下踱启,編譯器認(rèn)為,調(diào)用泛型方法后研底,其返回值被賦給一個(gè)Object類型的變量埠偿。

public class LimitsOfInference {
    static void f(Map<Person, List<? extends Pet>> petPeople) {}

    public static void main(String[] args) {
        f(New.mapOf()); // compile error before java8
    }
}

顯式的類型說明

在泛型的方法中,可以顯示的指明類型榜晦,不過這種語法非常少用冠蒋。要顯示的指明類型,必須在點(diǎn)操作符與方法名之間插入尖括號(hào)乾胶,然后將類型置于尖括號(hào)內(nèi)抖剿。如果是定義該方法的類的內(nèi)部,必須在點(diǎn)操作符之前使用this關(guān)鍵字识窿,如果是使用static的方法斩郎,必須在點(diǎn)操作符之前加上類名,這種寫法看解決LimitsOfInference中的問題喻频。

public class LimitsOfInference {
    static void f(Map<Person, List<Pet>> petPeople) {
    }

    public static void main(String[] args) {
        f(New.<Person, List<Pet>>mapOf());
    }
}

泛型和可變參數(shù)列表也能夠很好的共存

public class GenericVarargs {
    public static <T> List<T> makeList(T... args) {
        List<T> result = new ArrayList<>();
        for (T item : args) {
            result.add(item);
        }
        return result;
    }

    public static void main(String[] args) {
        List<String> ls = makeList("A");
        System.out.println("ls = " + ls);
        ls = makeList("A", "B", "C");
        System.out.println("ls = " + ls);
        ls = makeList("ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""));
        System.out.println("ls = " + ls);
    }
}
// Outputs
ls = [A]
ls = [A, B, C]
ls = [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缩宜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子甥温,更是在濱河造成了極大的恐慌锻煌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姻蚓,死亡現(xiàn)場離奇詭異宋梧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)狰挡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門捂龄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來释涛,“玉大人,你說我怎么就攤上這事跺讯∈嗷撸” “怎么了殉农?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵刀脏,是天一觀的道長。 經(jīng)常有香客問我超凳,道長愈污,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任轮傍,我火速辦了婚禮暂雹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘创夜。我一直安慰自己杭跪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布驰吓。 她就那樣靜靜地躺著涧尿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪檬贰。 梳的紋絲不亂的頭發(fā)上姑廉,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音翁涤,去河邊找鬼桥言。 笑死,一個(gè)胖子當(dāng)著我的面吹牛葵礼,可吹牛的內(nèi)容都是我干的号阿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼鸳粉,長吁一口氣:“原來是場噩夢啊……” “哼扔涧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赁严,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對情侶失蹤扰柠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后疼约,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卤档,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年程剥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了劝枣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汤踏。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖舔腾,靈堂內(nèi)的尸體忽然破棺而出溪胶,到底是詐尸還是另有隱情,我是刑警寧澤稳诚,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布哗脖,位于F島的核電站,受9級(jí)特大地震影響扳还,放射性物質(zhì)發(fā)生泄漏才避。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一氨距、第九天 我趴在偏房一處隱蔽的房頂上張望桑逝。 院中可真熱鬧,春花似錦俏让、人聲如沸楞遏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寡喝。三九已至,卻和暖如春沙廉,著一層夾襖步出監(jiān)牢的瞬間拘荡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工撬陵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留珊皿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓巨税,卻偏偏與公主長得像蟋定,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子草添,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容