中的占位符如何配合extends關(guān)鍵字使用,形如。泛型定義存在于這三種形式中:泛型類、泛型接口、泛型方法。 一般的泛型定義中的..."/>
溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java泛型extends關(guān)鍵字設(shè)置邊界的實(shí)現(xiàn)

發(fā)布時(shí)間:2020-09-03 05:52:40 來源:腳本之家 閱讀:165 作者:anlian523 欄目:編程語言

本文主要介紹在泛型定義中的< >中的占位符如何配合extends關(guān)鍵字使用,形如<T extends Integer>。泛型定義存在于這三種形式中:泛型類、泛型接口、泛型方法。

  • 一般的泛型定義中的<T>,相當(dāng)于<T extends Object>,而類型擦除則會(huì)將類型參數(shù)擦除成T的上界,即Object。則在泛型定義中作為T類型的對(duì)象可以調(diào)用Object的函數(shù)和屬性。
  • 使用了extends的泛型定義中的<T extends Integer>,其上界已被明顯定義了,此時(shí)會(huì)將類型參數(shù)擦除成Integer。則在泛型定義中作為T類型的對(duì)象可以調(diào)用Integer的函數(shù)和屬性。

接下來本文將以幾個(gè)示例和具體分析來講解剩下的知識(shí)點(diǎn)。

類型參數(shù)多邊界的分析

此例中的泛型類,類型參數(shù)帶有多個(gè)邊界。講下類的實(shí)際意義:Dimension代表物體的方位、HasColor代表物體的顏色、Weight代表物體的重量。

interface HasColor { java.awt.Color getColor(); }

class Colored<T extends HasColor> {
  T item;
  Colored(T item) { this.item = item; }
  T getItem() { return item; }
  // The bound allows you to call a method:
  java.awt.Color color() { return item.getColor(); }
}

class Dimension { public int x, y, z; }

// This won't work -- class must be first, then interfaces:
// class ColoredDimension<T extends HasColor & Dimension> { }

// Multiple bounds:
class ColoredDimension<T extends Dimension & HasColor> {
  T item;
  ColoredDimension(T item) { this.item = item; }
  T getItem() { return item; }
  java.awt.Color color() { return item.getColor(); }
  int getX() { return item.x; }
  int getY() { return item.y; }
  int getZ() { return item.z; }
}

interface Weight { int weight(); }

// As with inheritance, you can have only one
// concrete class but multiple interfaces:
class Solid<T extends Dimension & HasColor & Weight> {
  T item;
  Solid(T item) { this.item = item; }
  T getItem() { return item; }
  java.awt.Color color() { return item.getColor(); }
  int getX() { return item.x; }
  int getY() { return item.y; }
  int getZ() { return item.z; }
  int weight() { return item.weight(); }
}

class Bounded extends Dimension implements HasColor, Weight {
  public java.awt.Color getColor() { return null; }
  public int weight() { return 0; }
}

public class BasicBounds {
  public static void main(String[] args) {
    Solid<Bounded> solid = new Solid<Bounded>(new Bounded());
    solid.color();
    solid.getY();
    solid.weight();
  }
} ///:~
  • class Colored<T extends HasColor>這個(gè)泛型類的泛型定義中,要求了類型參數(shù)T的邊界為HasColor,正因如此,在函數(shù)java.awt.Color color() { return item.getColor(); }中便可以通過一個(gè)T類型的變量item來調(diào)用屬于HasColor的方法。
  • class ColoredDimension<T extends HasColor & Dimension> { },此時(shí)定義了邊界同時(shí)為HasColor & Dimension,但是由于編譯器要求占位符后的extends后第一個(gè)必須是類,之后的必須是接口(這就和正常的類的繼承規(guī)則一樣),所以此句通不過編譯。而class ColoredDimension<T extends Dimension & HasColor>給出了正確的定義,即第一個(gè)必須是類,之后的必須是接口。
  • class ColoredDimension<T extends Dimension & HasColor>的類定義中,因?yàn)門的邊界是HasColor & Dimension,所以在類定義中,既可以獲取Dimension的屬性,也可以調(diào)用HasColor的方法。
  • class Solid<T extends Dimension & HasColor & Weight>的類定義中,extends后第一個(gè)是類,之后的都是接口,符合剛才講的規(guī)則。同理,也可以從這些邊界中,獲取屬性,調(diào)用方法。
  • class Bounded extends Dimension implements HasColor, Weight這個(gè)類將在生成泛型類對(duì)象,用來指定具體類型為Bounded。因?yàn)閏lass Solid<T extends Dimension & HasColor & Weight>的類型參數(shù)T的要求是extends Dimension & HasColor & Weight,所以指定具體類型為new Solid<Bounded>,是可以的。因?yàn)轭惗x中構(gòu)造器的聲明為Solid(T item),且具體類型為new Solid<Bounded>中指定的Bounded,所以要求構(gòu)造器的實(shí)參為Bounded或者Bounded的子類。
class derivedBounded extends Bounded {}

class Bounded1 extends Dimension implements HasColor, Weight {
  public java.awt.Color getColor() { return null; }
  public int weight() { return 0; }
}

public class BasicBounds {
  public static void main(String[] args) {
    //Solid<Bounded> solid = new Solid<Integer>(new derivedBounded());//給定的具體類型不符合邊界
    Solid<Bounded> solid1 = new Solid<Bounded>(new derivedBounded());//可以傳遞具體類型Bounded的子類
    //Solid<Bounded> solid2 = new Solid<Bounded>(new Bounded1());//編譯報(bào)錯(cuò),因?yàn)榉盒偷撵o態(tài)類型檢查
    solid1.color();
    solid1.getY();
    solid1.weight();
  }
} ///:~

 根據(jù)上一條,那么new Solid<Integer>(new Bounded())這里指定的具體類型,由于和泛型類定義的T類型參數(shù)的要求extends Dimension & HasColor & Weight不相符,所以編譯會(huì)報(bào)錯(cuò);給構(gòu)造器傳值時(shí),實(shí)參可以是Bounded的子類;一個(gè)同樣繼承了相同邊界的類Bounded1 ,不能傳遞給構(gòu)造器,因?yàn)轭愋鸵呀?jīng)被指定為Bounded了。

但是類型參數(shù)有多個(gè)邊界時(shí),java內(nèi)部即java字節(jié)碼到底是怎么處理的呢:

 public static void main(java.lang.String[]);
  Code:
    0: new      #2         // class Solid
    3: dup
    4: new      #3         // class Bounded
    7: dup
    8: invokespecial #4         // Method Bounded."<init>":()V
   11: invokespecial #5         // Method Solid."<init>":(LDimension;)V
   14: astore_1

從Method Solid."<init>":(LDimension;)V可以看到,給Solid的構(gòu)造器傳遞參數(shù)時(shí),編譯器認(rèn)為這個(gè)形參是個(gè)Dimension,這就是編譯器處理多個(gè)邊界的方法,永遠(yuǎn)處理為第一個(gè)邊界,即類型擦除為第一個(gè)邊界。但剩下的兩個(gè)邊界怎么辦呢,這里都被處理第一個(gè)邊界了,我們?cè)偃タ匆幌耂olid.class的反編譯代碼就能找到答案:

// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)

import java.awt.Color;

class Solid<T extends Dimension & HasColor & Weight> {
  T item;

  Solid(T item) {
    this.item = item;
  }

  T getItem() {
    return this.item;
  }

  Color color() {
    return ((HasColor)this.item).getColor();//類型轉(zhuǎn)換為其他邊界,再調(diào)用方法
  }

  int getX() {
    return this.item.x;
  }

  int getY() {
    return this.item.y;
  }

  int getZ() {
    return this.item.z;
  }

  int weight() {
    return ((Weight)this.item).weight();//類型轉(zhuǎn)換為其他邊界,再調(diào)用方法
  }
}

當(dāng)調(diào)用的方法不屬于第一個(gè)邊界時(shí),就進(jìn)行類型轉(zhuǎn)換處理為其他邊界就行,反正T肯定是符合extends Dimension & HasColor & Weight的。

繼承有邊界要求的泛型類

通過觀察上例可知,Colored、ColoredDimension、Solid這三個(gè)類在持有對(duì)象的方面有冗余的地方:都有同一個(gè)成員變量、同一個(gè)構(gòu)造器、同一個(gè)get函數(shù)。而類型參數(shù)上,邊界也是依次疊加的。同樣,對(duì)于這些邊界所帶來的屬性和方法,也是冗余的。
所以下例對(duì)其進(jìn)行了修改,通過繼承來消除冗余,注意,下面繼承的泛型類對(duì)類型參數(shù)是有邊界要求的:

//HoldItem對(duì)邊界T沒有要求
class HoldItem<T> {
  T item;
  HoldItem(T item) { this.item = item; }
  T getItem() { return item; }
}
//Colored2對(duì)邊界T有HasColor的要求
class Colored2<T extends HasColor> extends HoldItem<T> {
  Colored2(T item) { super(item); }
  java.awt.Color color() { return item.getColor(); }
}
//ColoredDimension2對(duì)邊界T有Dimension & HasColor的要求
class ColoredDimension2<T extends Dimension & HasColor>
    extends Colored2<T> {
  ColoredDimension2(T item) { super(item); }
  int getX() { return item.x; }
  int getY() { return item.y; }
  int getZ() { return item.z; }
}
//Solid2對(duì)邊界T有Dimension & HasColor & Weight的要求,不過沒有類繼承它了
class Solid2<T extends Dimension & HasColor & Weight>
    extends ColoredDimension2<T> {
  Solid2(T item) { super(item); }
  int weight() { return item.weight(); }
}

public class InheritBounds {
  public static void main(String[] args) {
    Solid2<Bounded> solid2 =
        new Solid2<Bounded>(new Bounded());
    solid2.color();
    solid2.getY();
    solid2.weight();
  }
} ///:~
  • HoldItem這個(gè)泛型類通過類型參數(shù)T把成員變量、構(gòu)造器、get函數(shù)都定義好了,之后的類通過繼承它就可以獲得這些屬性和方法。
  • Colored2泛型類繼承了HoldItem,獲得了后者的屬性和方法從而減少了冗余。同時(shí),class Colored2<T extends HasColor>屬于“定義泛型類”,extends HoldItem<T>屬于“使用泛型類”,使用泛型類需要指定具體類型,現(xiàn)在確定具體類型的任務(wù)延后到了<T extends HasColor>的確認(rèn)。再從邊界是否符合的情況分析,HoldItem的要求是<T>屬于無邊界,<T extends HasColor>這樣的邊界定義屬于HasColor邊界,從范圍上說<T extends HasColor>是小于等于<T>的,這樣是可以的。由于T添加了HasColor邊界,所以可以調(diào)用item.getColor()方法了。
  • ColoredDimension2泛型類繼承了Colored2。從邊界是否符合的情況分析,Colored2對(duì)T的邊界要求是<T extends HasColor>,而ColoredDimension2定義中的T的邊界是<T extends Dimension & HasColor>,<T extends Dimension & HasColor>小于等于<T extends HasColor>,符合要求。換句話說,ColoredDimension2定義中的T的邊界必須比Colored2的邊界要求一致,或者范圍更小。
  • Solid2泛型類繼承了ColoredDimension2。從邊界是否符合的情況分析,<T extends Dimension & HasColor & Weight>小于等于ColoredDimension2的邊界要求<T extends Dimension & HasColor>,符合要求。

總結(jié)一下:

當(dāng)一個(gè)泛型類繼承另一個(gè)泛型類時(shí)(前者屬于“定義泛型類”,后者屬于“使用泛型類”),且使用了同一個(gè)類型參數(shù)時(shí),定義泛型類的類型參數(shù)邊界定義一定要小于等于使用的那個(gè)泛型類的邊界要求。

泛型方法中的邊界定義

泛型方法中對(duì)類型參數(shù)的邊界定義,同樣也得符合使用的泛型類的邊界要求。此例中,泛型類同樣繼承別的泛型類,分析同上不贅述。講下類的實(shí)際意義:一系列接口代表了超能力、一系列類代表了超級(jí)英雄,它們擁有一個(gè)超能力的成員變量。

import java.util.*;

interface SuperPower {}
interface XRayVision extends SuperPower {
  void seeThroughWalls();
}
interface SuperHearing extends SuperPower {
  void hearSubtleNoises();
}
interface SuperSmell extends SuperPower {
  void trackBySmell();
}

class SuperHero<POWER extends SuperPower> {
  POWER power;
  SuperHero(POWER power) { this.power = power; }
  POWER getPower() { return power; }
}

class SuperSleuth<POWER extends XRayVision> extends SuperHero<POWER> {
  SuperSleuth(POWER power) { super(power); }
  void see() { power.seeThroughWalls(); }
}

class CanineHero<POWER extends SuperHearing & SuperSmell> extends SuperHero<POWER> {
  CanineHero(POWER power) { super(power); }
  void hear() { power.hearSubtleNoises(); }
  void smell() { power.trackBySmell(); }
}

class SuperHearSmell implements SuperHearing, SuperSmell {
  public void hearSubtleNoises() {}
  public void trackBySmell() {}
}

class DogBoy extends CanineHero<SuperHearSmell> {
  DogBoy() { super(new SuperHearSmell()); }
}

public class EpicBattle {
  // Bounds in generic methods:
  static <POWER extends SuperHearing>
  void useSuperHearing(SuperHero<POWER> hero) {//泛型方法
    hero.getPower().hearSubtleNoises();
  }
  static <POWER extends SuperHearing & SuperSmell>
  void superFind(SuperHero<POWER> hero) {//泛型方法
    hero.getPower().hearSubtleNoises();
    hero.getPower().trackBySmell();
  }
  public static void main(String[] args) {
    DogBoy dogBoy = new DogBoy();
    useSuperHearing(dogBoy);
    superFind(dogBoy);
    // You can do this:
    List<? extends SuperHearing> audioBoys;
    // But you can't do this:
    // List<? extends SuperHearing & SuperSmell> dogBoys;
  }
} ///:~

  •  主函數(shù)中的useSuperHearing泛型方法中,其對(duì)T的邊界定義為<POWER extends SuperHearing>。而在形參中使用了泛型類SuperHero<POWER>,其對(duì)邊界的要求是<POWER extends SuperPower>。因?yàn)镾uperHearing繼承了SuperPower,所以邊界定義符合了對(duì)邊界的要求。
  • 主函數(shù)中的useSuperHearing泛型方法中,其對(duì)T的邊界定義為<POWER extends SuperHearing>。正因如此,在方法中便可以調(diào)用SuperHearing的方法hearSubtleNoises了。

其他

本文例子均來自java編程思想,例子本身不錯(cuò),但奈何作者對(duì)其做的講解很少,所以本人為其加上了詳細(xì)的分析。其實(shí)這些例子都需要反復(fù)琢磨,精讀之后才會(huì)對(duì)泛型的extends關(guān)鍵字有深刻的理解。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI