边界
边界的功能是可以用于泛型参数上设置限制条件,尽管这使得你可以强制规定泛型可以应用的类型,但是其潜在的一个更重要的效果是可以按照自己的边界类型来调用方法。
因为擦除移除了类型信息,所以,可以用无界泛型参数调用的方法只能是那些可以用Object
调用的方法。但是,如果能够将这个参数限制为某种类型的子集,那么就可以用这些类型子集来调用方法。
而为了执行这种限制,Java泛型重用了extends
关键字。这有一点很重要,即要理解extends
关键字在泛型边界上下文的情况和在普通情况所具有的意义是完全不同的。
下面的代码展示了边界的基本要素。
interface HasColor {
java.awt.Color getColor();
}
class Colored<T extends HasColor> {
T item;
Colored(T item) {
this.item = item;
}
T getItem() {
return item;
}
java.awt.Color color() {
return item.getColor();
}
}
class Dimension {
public int x, y, z;
}
// 这将无法通过编译,第一个必须是类,然后才是接口
//class ColloredDimension<T extends HasColor & Dimension> {
//}
class ColoredDimension<T extends Dimension & HasColor> {
T item;
public 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 {
@Override
public Color getColor() {
return null;
}
@Override
public int weight() {
return 0;
}
}
public class BaseBounds {
public static void main(String[] args) {
Solid<Bounded> solid = new Solid<>(new Bounded());
solid.color();
solid.getY();
solid.weight();
}
}
BasicBounds.java
看上去可以通过继承消除冗余。下面,看到如果在继承的每个层次上添加边界。
class HoldItem<T> {
T item;
HoldItem(T item) {
this.item = item;
}
T getItem() {
return item;
}
}
class Colored2<T extends HasColor> extends HoldItem<T> {
Colored2(T item) {
super(item);
}
java.awt.Color color() {
return item.getColor();
}
}
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;
}
}
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<>(new Bounded());
solid2.color();
solid2.getY();
solid2.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;
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 {
@Override
public void hearSubtleNoises() {
}
@Override
public void trackBySmell() {
}
}
class DogBoy extends CanineHero<SuperHearSmell> {
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 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;
}
}
通配符将被限制为单一边界。