1、泛型數組
因爲有了擦除,數組運行時的類型只能是Object[],如果我們立即將其轉型爲T[],那麼在編譯器該數組的實際類型就將丟失,而編譯器可能會錯過某些潛在的錯誤檢查,因此,最好在集合內部使用Object[],然後當使用數組元素時,添加一個對T的轉型。
public class GenericArray2<T> {
private Object[] array;
public GenericArray2(int sz) {
this.array = (T[]) new Object[sz];
}
public void put(int index, T item) {
array[index] = item;
}
public T get(int index) {
return (T) array[index];
}
public T[] rep() {
return (T[]) array;
}
public static void main(String[] args) {
GenericArray2<Integer> integerGenericArray = new GenericArray2<>(10);
for (int i = 0; i < 10; i++) {
integerGenericArray.put(i, i);
}
for (int i = 0; i < 10; i++) {
System.out.println(integerGenericArray.get(i) + "");
}
System.out.println();
try{
Integer[] rep = integerGenericArray.rep();
}catch (Exception e){
System.out.println(e);
}
}
}
現在內部是Object[]而不是T[],當get被調用時,他將對象轉型爲T,實際上是正確的類型,因此是安全的。然而,在調用rep的時候,將Object[]轉型爲T[],仍舊是不正確的。沒有任何方式可以推翻底層的數組類型,只能是Object[]。在內部將array當作Object[]而不是T[]處理的優勢是:我們不太可能忘記這個數組的運行時類型學想,從而以外地引入缺陷(儘管大多數也可能是所有這類缺陷都可以在運行時快速探測到)
通過傳遞類型標記完成泛型數組:
public class GenericArrayWithTypeToken<T> {
private T[] array;
public GenericArrayWithTypeToken(Class<T> type,int sz) {
this.array = (T[]) Array.newInstance(type,sz);
}
public void put(int index, T item) {
array[index] = item;
}
public T get(int index) {
return (T) array[index];
}
public T[] rep() {
return array;
}
public static void main(String[] args) {
GenericArrayWithTypeToken<Integer> integerGenericArrayWithTypeToken = new GenericArrayWithTypeToken<>(Integer.class, 10);
Integer[] rep = integerGenericArrayWithTypeToken.rep();
}
}
類型標記Class<T>被傳遞到構造器中,以便從擦除中恢復,使得我們可以創建需要的實際類型的數組。可以將運行時類型轉爲確切類型T[]
2、邊界
邊界可以在用於泛型的參數類型上設置限制條件。也可以強制規定泛型可以應用的類型,但是其潛在的一個更重要的效果是可以按照自己的邊界類型來調用方法。
因爲擦除移除了類型信息,所以無界泛型參數調用的方法只是那些可以用Object調用的方法。爲了將這個參數限制爲某個類型的子集,然後用這些類型子集調用方法,泛型重用了extends關鍵字。
interface HasColor{java.awt.Color getColor();}
class Colored<T extends HasColor>{
T item;
public Colored(T item) {
this.item = item;
}
public T getItem() {
return item;
}
java.awt.Color color(){return item.getColor();}
}
class Dimension {public int x,y,z;}
// class 需要放在第一個
//class ColoredDimension<T extends HasColor&Dimension>
class ColoredDimension<T extends Dimension&HasColor>{
T item;
public ColoredDimension(T item) {
this.item = item;
}
public 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();}
class Solid<T extends Dimension &HasColor&Weight>{
T item;
public Solid(T item) {
this.item = item;
}
public 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{
@Override
public Color getColor() {
return null;
}
@Override
public int weight() {
return 0;
}
}
public class BasicBounds {
public static void main(String[] args) {
Solid<Bounded> boundedSolid = new Solid<>(new Bounded());
boundedSolid.color();
boundedSolid.weight();
boundedSolid.getY();
}
}
看上去可以通過繼承消除包含冗餘,下面看如何在繼承的每個層次上添加邊界限制。
class HoldItem<T> {
T item;
public HoldItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
class Colored2<T extends HasColor> extends HoldItem<T> {
public Colored2(T item) {
super(item);
}
java.awt.Color color() {
return item.getColor();
}
}
class ColoredDimension2<T extends Dimension & HasColor> extends Colored2<T> {
public ColoredDimension2(T item) {
super(item);
}
int getX() {
return item.x;
}
int getY() {
return item.y;
}
int getZ() {
return item.z;
}
}
class Solid2<T extends Dimension & HasColor & Weight> extends ColoredDimension2<T> {
public Solid2(T item) {
super(item);
}
int weight() {
return item.weight();
}
}
public class InheritBounds {
public static void main(String[] args) {
Solid2<Bounded> boundedSolid2 = new Solid2<>(new Bounded());
boundedSolid2.color();
boundedSolid2.getY();
boundedSolid2.weight();
}
}
HoldItem直接持有一個都系,因此這種行爲被繼承到Colored2中,它要求參數和HasColor一致。ColoredDimension2和Solid2進一步擴展了這個層級結構,並在每個層次上添加了邊界。現在這些方法被繼承,因而不必在每個類中重複
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;
public SuperHero(POWER power) {
this.power = power;
}
public POWER getPower() {
return power;
}
}
class SuperSleuth<POWER extends XRayVision> extends SuperHero<POWER> {
public SuperSleuth(POWER power) {
super(power);
}
void see() {
power.seeThroughWalls();
}
}
class CanineHero<POWER extends SuperHearing & SuperSmell> extends SuperHero<POWER> {
public CanineHero(POWER power) {
super(power);
}
void hear() {
power.hearSubtleNoises();
}
void smell() {
power.trackBySmell();
}
}
class SuperHearSmell implements SuperHearing, SuperSmell {
@Override
public void hearSubtleNoises() {
}
@Override
public void trackBySmell() {
}
}
class DogBoy extends CanineHero<SuperHearSmell> {
public DogBoy() {
super(new SuperHearSmell());
}
}
public class EpicBattle {
static <POWER extends SuperHearing> void useSuperHearing(SuperHero<POWER> hero) {
hero.getPower().hearSubtleNoises();
}
static <POWER extends SuperHearing & SuperSmell> void useFind(SuperHero<POWER> hero) {
hero.getPower().hearSubtleNoises();
hero.getPower().trackBySmell();
}
public static void main(String[] args) {
DogBoy dogBoy = new DogBoy();
useSuperHearing(dogBoy);
useFind(dogBoy);
// ?被限制爲單一邊界 因此報錯
// List<? extends SuperHearing&SuperSmell > dogBoys;
}
}
通配符?被限制爲單一邊界
Thinking In Java Part11(泛型數組、通過extends限制邊界)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.