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限制边界)
最新推荐文章于 2021-02-16 15:28:28 发布
本文深入探讨了Java泛型中的泛型数组和边界的概念,解释了为何在泛型类中使用Object[]而非T[],以及如何通过类型标记解决泛型数组的问题。此外,还详细讲解了如何使用边界限制泛型参数,使其能够调用特定类型的方法,以及在继承层次结构中如何添加和使用边界限制。
1018

被折叠的 条评论
为什么被折叠?



