本篇文章为大家展示了Java中怎么利用extends关键字设置边界,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:国际域名空间、网站空间、营销软件、网站建设、鹿邑网站维护、网站推广。
类型参数多边界的分析
此例中的泛型类,类型参数带有多个边界。讲下类的实际意义:Dimension代表物体的方位、HasColor代表物体的颜色、Weight代表物体的重量。
interface HasColor { java.awt.Color getColor(); }class Colored { 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 { }// Multiple bounds:class ColoredDimension { 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 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 solid = new Solid(new Bounded()); solid.color(); solid.getY(); solid.weight(); }} ///:~
class Colored这个泛型类的泛型定义中,要求了类型参数T的边界为HasColor,正因如此,在函数java.awt.Color color() { return item.getColor(); }中便可以通过一个T类型的变量item来调用属于HasColor的方法。 class ColoredDimension { },此时定义了边界同时为HasColor & Dimension,但是由于编译器要求占位符后的extends后第一个必须是类,之后的必须是接口(这就和正常的类的继承规则一样),所以此句通不过编译。而class ColoredDimension给出了正确的定义,即第一个必须是类,之后的必须是接口。 class ColoredDimension的类定义中,因为T的边界是HasColor & Dimension,所以在类定义中,既可以获取Dimension的属性,也可以调用HasColor的方法。 class Solid的类定义中,extends后第一个是类,之后的都是接口,符合刚才讲的规则。同理,也可以从这些边界中,获取属性,调用方法。 class Bounded extends Dimension implements HasColor, Weight这个类将在生成泛型类对象,用来指定具体类型为Bounded。因为class Solid的类型参数T的要求是extends Dimension & HasColor & Weight,所以指定具体类型为new Solid,是可以的。因为类定义中构造器的声明为Solid(T item),且具体类型为new Solid中指定的Bounded,所以要求构造器的实参为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 solid = new Solid(new derivedBounded());//给定的具体类型不符合边界 Solid solid1 = new Solid(new derivedBounded());//可以传递具体类型Bounded的子类 //Solid solid2 = new Solid(new Bounded1());//编译报错,因为泛型的静态类型检查 solid1.color(); solid1.getY(); solid1.weight(); }} ///:~
根据上一条,那么new Solid(new Bounded())这里指定的具体类型,由于和泛型类定义的T类型参数的要求extends Dimension & HasColor & Weight不相符,所以编译会报错;给构造器传值时,实参可以是Bounded的子类;一个同样继承了相同边界的类Bounded1 ,不能传递给构造器,因为类型已经被指定为Bounded了。
但是类型参数有多个边界时,java内部即java字节码到底是怎么处理的呢:
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."":()V 11: invokespecial #5 // Method Solid."":(LDimension;)V 14: astore_1
从Method Solid."":(LDimension;)V可以看到,给Solid的构造器传递参数时,编译器认为这个形参是个Dimension,这就是编译器处理多个边界的方法,永远处理为第一个边界,即类型擦除为第一个边界。但剩下的两个边界怎么办呢,这里都被处理第一个边界了,我们再去看一下Solid.class的反编译代码就能找到答案:
// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)import java.awt.Color;class Solid { T item; Solid(T item) { this.item = item; } T getItem() { return this.item; } Color color() { return ((HasColor)this.item).getColor();//类型转换为其他边界,再调用方法 } 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();//类型转换为其他边界,再调用方法 }}
当调用的方法不属于第一个边界时,就进行类型转换处理为其他边界就行,反正T肯定是符合extends Dimension & HasColor & Weight的。
继承有边界要求的泛型类
通过观察上例可知,Colored、ColoredDimension、Solid这三个类在持有对象的方面有冗余的地方:都有同一个成员变量、同一个构造器、同一个get函数。而类型参数上,边界也是依次叠加的。同样,对于这些边界所带来的属性和方法,也是冗余的。所以下例对其进行了修改,通过继承来消除冗余,注意,下面继承的泛型类对类型参数是有边界要求的:
//HoldItem对边界T没有要求class HoldItem { T item; HoldItem(T item) { this.item = item; } T getItem() { return item; }}//Colored2对边界T有HasColor的要求class Colored2 extends HoldItem { Colored2(T item) { super(item); } java.awt.Color color() { return item.getColor(); }}//ColoredDimension2对边界T有Dimension & HasColor的要求class ColoredDimension2 extends Colored2 { ColoredDimension2(T item) { super(item); } int getX() { return item.x; } int getY() { return item.y; } int getZ() { return item.z; }}//Solid2对边界T有Dimension & HasColor & Weight的要求,不过没有类继承它了class Solid2 extends ColoredDimension2 { Solid2(T item) { super(item); } int weight() { return item.weight(); }}public class InheritBounds { public static void main(String[] args) { Solid2 solid2 = new Solid2(new Bounded()); solid2.color(); solid2.getY(); solid2.weight(); }} ///:~
HoldItem这个泛型类通过类型参数T把成员变量、构造器、get函数都定义好了,之后的类通过继承它就可以获得这些属性和方法。 Colored2泛型类继承了HoldItem,获得了后者的属性和方法从而减少了冗余。同时,class Colored2属于“定义泛型类”,extends HoldItem属于“使用泛型类”,使用泛型类需要指定具体类型,现在确定具体类型的任务延后到了的确认。再从边界是否符合的情况分析,HoldItem的要求是属于无边界,这样的边界定义属于HasColor边界,从范围上说是小于等于的,这样是可以的。由于T添加了HasColor边界,所以可以调用item.getColor()方法了。 ColoredDimension2泛型类继承了Colored2。从边界是否符合的情况分析,Colored2对T的边界要求是,而ColoredDimension2定义中的T的边界是,小于等于,符合要求。换句话说,ColoredDimension2定义中的T的边界必须比Colored2的边界要求一致,或者范围更小。 Solid2泛型类继承了ColoredDimension2。从边界是否符合的情况分析,小于等于ColoredDimension2的边界要求,符合要求。
总结一下:
当一个泛型类继承另一个泛型类时(前者属于“定义泛型类”,后者属于“使用泛型类”),且使用了同一个类型参数时,定义泛型类的类型参数边界定义一定要小于等于使用的那个泛型类的边界要求。
泛型方法中的边界定义
泛型方法中对类型参数的边界定义,同样也得符合使用的泛型类的边界要求。此例中,泛型类同样继承别的泛型类,分析同上不赘述。讲下类的实际意义:一系列接口代表了超能力、一系列类代表了超级英雄,它们拥有一个超能力的成员变量。
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 power; SuperHero(POWER power) { this.power = power; } POWER getPower() { return power; }}class SuperSleuth extends SuperHero { SuperSleuth(POWER power) { super(power); } void see() { power.seeThroughWalls(); }}class CanineHero extends SuperHero { 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 { DogBoy() { super(new SuperHearSmell()); }}public class EpicBattle { // Bounds in generic methods: static void useSuperHearing(SuperHero hero) {//泛型方法 hero.getPower().hearSubtleNoises(); } static void superFind(SuperHero 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; }} ///:~
主函数中的useSuperHearing泛型方法中,其对T的边界定义为。而在形参中使用了泛型类SuperHero,其对边界的要求是。因为SuperHearing继承了SuperPower,所以边界定义符合了对边界的要求。 主函数中的useSuperHearing泛型方法中,其对T的边界定义为。正因如此,在方法中便可以调用SuperHearing的方法hearSubtleNoises了。
上述内容就是Java中怎么利用extends关键字设置边界,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注创新互联行业资讯频道。
网站栏目:Java中怎么利用extends关键字设置边界
本文链接:
http://mswzjz.cn/article/ijhisd.html