##################################################

目录

多态

什么是多态

为什么使用多态

向上转换/子类到父类的转换

使用父类作为方法形参实现多态

使用父类作为方法返回值实现多态

向下转换/父类到子类的转换

基本类型和引用类型强制转换对比不同

instanceof 运算符


##################################################

多态

——————————

什么是多态

多态是 Java 中非常重要的内容

多态不仅可以减少代码量 还可以提高代码的可扩展性和可维护性

多态/polymorphism 是具有表现多种形态的能力的特征即同一个实现接口使用不同的实例执行不同的操作

    打印机可以看作一个父类黑白打印机和彩色打印机是打印机的两个子类父类打印机中的打印方法在每个子类中都有不同的实现方式例如对黑白打印机执行打印操作后打印效果是黑白色的而对彩色打印机执行打印操作后打印效果是彩色的很明显子类分别对父类的打印方法进行了重写从这里也可以看出多态性与继承、方法重写密切相关!

多态的三个条件:

存在继承        继承是多态的基础 没有继承就不会有多态!

子类重写父类的方法        多态下调用子类重写后的方法!

父类引用变量指向子类对象        子类到父类的类型转换

——————————

为什么使用多态

来看一段代码

首先创建枪类 是所有枪械的父类 这是一个抽象类

增加抽象方法 R 装弹

枪类:

package mmain;public abstract class Qiang {
/* 枪类 各种枪械的父类 是一个抽象类 *//* —————————— 私密属性 —————————— */private String name; // 枪名private int sheCheng;  // 射程private int rongLiang; // 容量private double zhongLiang; // 重量/* —————————— 构造方法 —————————— */public Qiang (String name) {/* 构造方法 设置枪械名字 */this.name = name;}/* —————————— 普通方法 —————————— */public String getName () {/* 获取枪械名 */return this.name;}public int getSC () {/* 获取射程 */return this.sheCheng;}public void setSC (int sheCheng) {/* 设置射程 */this.sheCheng = sheCheng;}public int getRL () {/* 获取容量 */return this.rongLiang;}public void setRL (int rongLiang) {/* 设置容量 */this.rongLiang += rongLiang;   // 是 += 结果加上参数}public double getZL () {/* 获取重量 */return this.zhongLiang;}public void setZL (double zhongLiang) {/* 设置重量 */this.zhongLiang = zhongLiang;}public void print () {/* 输出信息 */System.out.printf ( "这是 %s, 射程 %d, 容量 %d, 重量 %f..", this.name, this.getSC(), this.getRL(), getZL() );}/* —————————— 抽象方法 —————————— */public abstract void R ();   // 抽象方法 装弹!
}

让手枪类重写枪类的装弹方法以实现手枪装弹!

手枪类:

package mmain;public class ShouQiang extends Qiang {
/* 手枪类 继承自抽象枪类 */private String thisName;   // 本手枪类名字public ShouQiang (String name, String thisName) {/* 本类带参构造 */super (name); // 通过 super 关键字调用构造this.thisName = thisName;}public void print() {/* 重写父类的输出方法 */super.print();    // 通过 super 关键字调用方法System.out.printf ( "这是一把 %s 。", this.thisName );}public void R() {/* 实现父类的装弹方法 */super.setRL(12); // 一次装填 12 发子弹System.out.printf ( "为%s手枪弹药装填十二发!\n", super.getName() );}
}

让步枪类实现枪类的装弹方法以实现步枪装弹

步枪类:

package mmain;public class BuQiang extends Qiang {
/* 步枪类 是抽象枪类的子类 */private int thisSC;   // 本步枪类射程public BuQiang (String name, int thisSC) {/* 本类带参构造 */super (name);this.thisSC = thisSC;}public void print() {/* 重写父类的输出方法 */super.print();   // 通过 super 关键字调用方法System.out.printf ( "此步枪的射程为 %d 米。", this.thisSC );}public void R() {/* 实现父类的装弹方法 */super.setRL(30);   // 一次装填 30 发子弹System.out.printf ( "为%s步枪弹药装填三十发!\n", super.getName() );}
}

创建士兵类

通过 R 方法调用手枪类 R 方法实现手枪装弹

通过 R 方法调用步枪类 R 方法实现步枪装弹

士兵类:

package mmain;public class ShiBing {
/* 士兵类 */private String name = "士兵"; // 士兵姓名private int zdNum = 0;  // 弹药数public ShiBing (String name, int zdNum) {/* 本类构造 */this.name = name; // 添加士兵名字this.zdNum = zdNum;   // 添加士兵子弹}public void R(ShouQiang sq) {/* 重载方法 士兵給手枪装弹 参数类型为手枪类的对象!!! */sq.R();}public void R(BuQiang bq) {/* 重载方法 士兵給步枪装弹 参数类型为步枪类的对象!!! */bq.R();}
}

创建测试类

分别创建手枪、步枪、士兵等对象

调用相应的方法实现士兵为枪械装弹等功能!

主要类:

package mmain;public class Main {
/* 主要类 */public static void main(String[] args) {// 手枪类构造初始化信息ShouQiang sq = new ShouQiang ( "二鞋牌", "手枪" );// 步枪类构造初始化信息BuQiang bq = new BuQiang ( "汤姆牌", 200 );// 士兵类构造初始化信息ShiBing sb = null;sb = new ShiBing ( "冲田修一", 90 );sb.R(sq);    // 调用手枪装弹 参数为手枪类实例sb.R(bq); // 调用步枪装弹 参数为步枪类对象}
}

eclipse JavaSE-17 下编译运行:

为二鞋牌手枪弹药装填十二发!
为汤姆牌步枪弹药装填三十发!

此时我们已经实现了士兵給枪械装弹的功能

但是如果士兵此时又多了一把狙击枪呢?

当然你仍可以在士兵类中重载装弹 R()

那么又又又多出来轻机枪、战防炮呢?

每增加一样武器都需要修改士兵类的源代码 增加 R 重载方法

如果有十几样武器 士兵类中就会有很多的装弹重载方法!

仔细观察重载方法的参数类型她们都有一个共同的父类

能不能让士兵类中只有一个 R() 装弹方法可以实现对所有武器的装弹

这样就算士兵有上百样武器 都不需要修改士兵类的源代码

通过多态便可以实现这种效果!

——————————

向上转换/子类到父类的转换

还记得基本数据类型之间的转换吗?

    自动类型转换:
int a = 521;
double b = a;强制类型转换:
double b = 521.1314;
int a = (int) b;

实际上在引用数据类型的子类和父类之间也存在着类型转换问题!

    不涉及类型转换:
子类 对象名 = new 子类 ();
子类 对象名 = new 子类 ( 参数列表 );子类到父类的转换:
父类 对象名 = new 子类 ();
父类 对象名 = new 子类 ( 参数列表 );
父类.方法名 ();    /* 会调用子类重写的方法而不是父类的抽象方法 */
父类.子类方法名 ();    /* 编译错误 父类的引用无法调用子类特有的方法 */

可以总结出子类转换成父类的规则:

    将一个父类的引用指向一个子类对象 称为向上转型 upcasting 自动进行类型转换此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法 不是父类的方法此时通过父类引用变量无法调用子类特有的方法

——————————

使用父类作为方法形参实现多态

使用父类作为方法的形参是 Java 中实现和使用多态的主要方式之一!

修改我们的代码 在士兵类增加唯一的装弹重载方法 以父类作为形参!

package mmain;public class ShiBing {private String name = "士兵";private int zdNum = 0;public ShiBing (String name, int zdNum) {this.name = name;this.zdNum = zdNum;}public void R(Qiang q) {/* 唯一的重载方法 士兵給手枪装弹 参数类型为 枪类 的对象!!! */q.R();    // 此时调用的不是父类的抽象方法而是子类实现的方法!}
}

主要类的测试代码仍然不变:

package mmain;public class Main {public static void main(String[] args) {ShouQiang sq = new ShouQiang ( "二鞋牌", "手枪" );BuQiang bq = new BuQiang ( "汤姆牌", 250 );ShiBing sb = null;sb = new ShiBing ( "冲田修一", 90 );sb.R(sq);sb.R(bq);}
}

运行结果如下:

为二鞋牌手枪弹药装填十二发!
为汤姆牌步枪弹药装填三十发!

可以看到士兵类只是使用了一个装弹方法 使用父类作为方法形参就可以正确显示多个枪械的装弹方式!

无需再一个个编写代码了 大大减少了代码量!

现在更改测试代码 执行向上转换:

package mmain;public class Main {public static void main(String[] args) {Qiang sq = new ShouQiang ( "二鞋牌", "手枪" );  // 手枪向上转换到枪Qiang bq = new BuQiang ( "汤姆牌", 250 );    // 步枪向上转换到枪ShiBing sb = new ShiBing ( "冲田修一", 90 );sb.R(sq);sb.R(bq);}
}

运行结果仍然如下:

为二鞋牌手枪弹药装填十二发!
为汤姆牌步枪弹药装填三十发!

把实参赋給形参的过程中涉及了父类和子类之间的类型转换

执行 Qiang sq = new ShouQiang ( "二鞋牌", "手枪" ) 调用 R(q) 时会执行 sq.R()

调用的是 sq 对象真实引用的对象 ShouQiang 类的对象实例重写的 R 方法

执行 Qiang bq = new BuQiang ( "汤姆牌", 250 ) 调用 R(q) 会执行 bq.R()

调用的是 bq 对象真实引用的对象 BuQiang 类的对象实例重写的 R 方法

    我们可以发现使用父类作为方法形参优势明显 或者说使用多态的优势明显:
可以减少代码量
提高代码的可扩展性和可维护性

下面我们展示一下可扩展性 即使增加狙枪类机枪类也无须添加或修改装弹方法

现在增加狙枪类和机枪类全部继承枪类并重写装弹方法!

狙枪类:

package mmain;public class JuQiang extends Qiang {
/* 狙枪类 是抽象枪类的子类 */private int thisSC;   // 本狙射程public JuQiang (String name, int thisSC) {/* 本类带参构造 */super (name);this.thisSC = thisSC;}public void print() {/* 重写父类的输出方法 */super.print(); // 通过 super 关键字调用方法System.out.printf ( "此狙枪的射程为 %d 米。", this.thisSC );}public void R() {/* 实现父类的装弹方法 */super.setRL(10);   // 一次装填 10 发子弹System.out.printf ( "为%s狙枪弹药装填十发!\n", super.getName() );}
}

机枪类:

package mmain;public class JiQiang extends Qiang {
/* 机枪类 是抽象枪类的子类 */private int thisSC;   // 本机射程public JiQiang (String name, int thisSC) {/* 本类带参构造 */super (name);this.thisSC = thisSC;}public void print() {/* 重写父类的输出方法 */super.print(); // 通过 super 关键字调用方法System.out.printf ( "此机枪的射程为 %d 米。", this.thisSC );}public void R() {/* 实现父类的装弹方法 */super.setRL(60);   // 一次装填 60 发子弹System.out.printf ( "为%s机枪弹药装填六十发!\n", super.getName() );}
}

士兵类不变 主要类的测试代码改动一下:

package mmain;public class Main {public static void main(String[] args) {Qiang sq = new ShouQiang ( "二鞋牌", "手枪" );Qiang bq = new BuQiang ( "汤姆牌", 250 );ShiBing sb = new ShiBing ( "冲田修一", 90 );sb.R(sq);sb.R(bq);// 测试新武器Qiang jq_1 = new JuQiang ( "杰瑞牌", 250 );sb.R( jq_1 );Qiang jq_2 = new JiQiang ( "斯派克牌", 700 );sb.R( jq_2 );}
}

运行结果:

为二鞋牌手枪弹药装填十二发!
为汤姆牌步枪弹药装填三十发!
为杰瑞牌狙枪弹药装填十发!
为斯派克牌狙枪弹药装填六十发!

——————————

使用父类作为方法返回值实现多态

使用父类作为方法的返回值 是 Java 中实现和使用多态的另一种方式

修改我们的代码

修改士兵类 增加 gerQiang (int q_ID) 以父类 Qiang 作为返回值类型实现装弹功能!

士兵类如下:

package mmain;public class ShiBing {private String name = "士兵";private int zdNum = 0;public ShiBing (String name, int zdNum) {this.name = name;this.zdNum = zdNum;}public void R(Qiang q) {/* 实现父类的装弹方法 接收一个枪类对象 */q.R();  // 调用接收对象的装弹方法!}public Qiang getQiang(int q_ID) {/* 根据不同的 id 编号返回不同的枪类对象 */Qiang q = null;if ( q_ID == 1 )q = new ShouQiang ( "二鞋牌手枪", "手枪" );else if ( q_ID == 2 )q = new BuQiang ( "汤姆牌步枪", 250 );else if ( q_ID == 3 )q = new JuQiang ( "杰瑞牌狙枪", 250 );else if ( q_ID == 4 )q = new JiQiang ( "斯派克牌机枪", 700 );return q;}
}

主要类如下:

package mmain;import java.util.Scanner;public class Main {public static void main(String[] args) {System.out.printf ( "游戏开始!\n" );while ( test (true) )/* 死循环 */;;System.out.printf ( "士兵阵亡..游戏结束!\n" );}private static boolean test (boolean b) {/* 测试方法 */Scanner scInput = new Scanner ( System.in );System.out.printf ( "\n请选择要装填的武器类型\n" );System.out.printf ( "\t1 >>> 手枪\n" );System.out.printf ( "\t2 >>> 步枪\n" );System.out.printf ( "\t3 >>> 狙枪\n" );System.out.printf ( "\t4 >>> 机枪\n" );System.out.printf ( "请输入 1~4 编号 <<< " );ShiBing sb = new ShiBing ( "冲田修一", 90 );Qiang q = sb.getQiang ( scInput.nextInt() );if ( q != null ) {System.out.printf ( "装弹成功!" );sb.R ( q );} elseSystem.out.printf ( "没有该武器,装弹失败!\n" );// 接收值为 true 则默认情况下永远循环System.out.print ( "\n输入 0 结束程序\n<<< " );if ( scInput.nextInt() == 0 )b = false;return b;}
}

测试如下:

游戏开始!请选择要装填的武器类型1 >>> 手枪2 >>> 步枪3 >>> 狙枪4 >>> 机枪
请输入 1~4 编号 <<< 1
装弹成功!为二鞋牌手枪手枪弹药装填十二发!输入 0 结束程序
<<< 1请选择要装填的武器类型1 >>> 手枪2 >>> 步枪3 >>> 狙枪4 >>> 机枪
请输入 1~4 编号 <<< 2
装弹成功!为汤姆牌步枪步枪弹药装填三十发!输入 0 结束程序
<<< 2请选择要装填的武器类型1 >>> 手枪2 >>> 步枪3 >>> 狙枪4 >>> 机枪
请输入 1~4 编号 <<< 3
装弹成功!为杰瑞牌狙枪狙枪弹药装填十发!输入 0 结束程序
<<< 3请选择要装填的武器类型1 >>> 手枪2 >>> 步枪3 >>> 狙枪4 >>> 机枪
请输入 1~4 编号 <<< 4
装弹成功!为斯派克牌机枪狙枪弹药装填六十发!输入 0 结束程序
<<< 0
士兵阵亡..游戏结束!

如果以后武器增多只需要增加判断条件并创建枪类型的真实引用对象最后再于测试类添加宠物类型选项即可!

——————————

向下转换/父类到子类的转换

当向上转型发生后 将无法调用子类特有的方法

但是当需要调用子类特有的方法时 可以通过将父类再转换为子类来实现

将一个指向子类对象的父类引用赋給一个子类的引用称为向下转型此时必须进行强制类型转换

使用多态实现投手雷和开镜功能!

添加手雷类:

package mmain;public class Fwdh extends Qiang {
/* 手雷类 继承自枪类 */private int miao;    // 手雷爆破倒计时public Fwdh ( String name, int miao ) {/* 本类构造 */super(name);this.miao = miao;}public void R() {/* 实现父类的装弹方法 */super.setRL(1);   // 一次拿 1 颗雷System.out.printf ( "士兵获取%s1颗!\n", super.getName() );}public void fwdh() {/* 丢手雷方法 */System.out.printf ( "士兵正在丢手雷%d秒后爆炸!\n", this.miao );}
}

添加瞄准类:

package mmain;public class MiaoZhun extends Qiang {
/* 瞄准类 继承自枪类 */private int bei; // 狙击镜倍数public MiaoZhun(String name, int bei) {/* 本类构造 */super(name);this.bei = bei;}public void R() {/* 实现父类抽象 */super.setRL(1);  // 一次安装一个瞄具System.out.printf ( "士兵正在安装%s瞄具一个!\n", super.getName() );}public void miao() {/* 瞄准功能 */System.out.printf ( "士兵正在使用%d倍瞄准镜!\n", this.bei );}
}

为士兵类添加 giao 功能

如果 giao 代表 Fwdh 类则丢雷

如果 giao 代表 MiaoZhun 类则进行瞄准

士兵类:

package mmain;public class ShiBing {private String name = "士兵";private int zdNum = 0;public ShiBing (String name, int zdNum) {this.name = name;this.zdNum = zdNum;}public void R(Qiang q) {/* 实现父类的装弹方法 接收一个枪类对象 */q.R();  // 调用接收对象的装弹方法!}public Qiang getQiang(int q_ID) {/* 根据不同的 id 编号返回不同的枪类对象 */Qiang q = null;if ( q_ID == 1 )q = new ShouQiang ( "二鞋牌手枪", "手枪" );else if ( q_ID == 2 )q = new BuQiang ( "汤姆牌步枪", 250 );else if ( q_ID == 3 )q = new JuQiang ( "杰瑞牌狙枪", 250 );else if ( q_ID == 4 )q = new JiQiang ( "斯派克牌机枪", 700 );else if ( q_ID == 5 )q = new Fwdh ( "高爆雷", 5 );else if ( q_ID == 6 )q = new MiaoZhun ( "倍数瞄准镜", 8 );return q;}
}

主类增加选项:

package mmain;import java.util.Scanner;public class Main {public static void main(String[] args) {System.out.printf ( "游戏开始!\n" );while ( test (true) )/* 死循环 */;;System.out.printf ( "士兵阵亡..游戏结束!\n" );}private static boolean test (boolean b) {/* 测试方法 */Scanner scInput = new Scanner ( System.in );System.out.printf ( "\n请选择要装填的武器类型\n" );System.out.printf ( "\t1 >>> 手枪\n" );System.out.printf ( "\t2 >>> 步枪\n" );System.out.printf ( "\t3 >>> 狙枪\n" );System.out.printf ( "\t4 >>> 机枪\n" );System.out.printf ( "\t5 >>> 手雷\n" );System.out.printf ( "\t6 >>> 瞄具\n" );System.out.printf ( "请输入 1~4 编号 <<< " );ShiBing sb = new ShiBing ( "冲田修一", 90 );int i = scInput.nextInt();Qiang q = sb.getQiang ( i );if ( q != null ) {System.out.printf ( "装弹成功!" );sb.R ( q );} elseSystem.out.printf ( "没有该武器,装弹失败!\n" );// 接收值为 true 则默认情况下永远循环System.out.print ( "\n输入 0 结束程序\n<<< " );if ( scInput.nextInt() == 0 )b = false;return b;}
}

但这个时候就遇到了问题

之前的三个类都重写了装弹方法 方法名师一样的

但是现在 手雷类提供了手雷方法 瞄准类提供了瞄准方法 两个方法名不一样!

枪父类中并没有相应的抽象方法定义 这可要怎么投雷瞄准呐??!

此时就需要使用多态的另一个功能 父类到子类的转换!

同时也需要使用 instanceof 运算符来判断对象的类型!

如果把士兵对象赋給枪类型引用变量后又希望让士兵投雷 这显然是不可能的

编译错误 无法调用子类特有的方法:

此时就需要强制将父类型转换为子类型:

子类 之后使用的对象名 = (子类) 待转换的父类对象名;

我们应用到主要测试类的测试方法:

package mmain;import java.util.Scanner;public class Main {public static void main(String[] args) {System.out.printf ( "游戏开始!\n" );while ( test (true) )/* 死循环 */;;System.out.printf ( "士兵阵亡..游戏结束!\n" );}private static boolean test (boolean b) {/* 测试方法 */Scanner scInput = new Scanner ( System.in );System.out.printf ( "\n请选择要装填的武器类型\n" );System.out.printf ( "\t1 >>> 手枪\n" );System.out.printf ( "\t2 >>> 步枪\n" );System.out.printf ( "\t3 >>> 狙枪\n" );System.out.printf ( "\t4 >>> 机枪\n" );System.out.printf ( "\t5 >>> 手雷\n" );System.out.printf ( "\t6 >>> 瞄具\n" );System.out.printf ( "请输入 1~4 编号 <<< " );ShiBing sb = new ShiBing ( "冲田修一", 90 );int i = scInput.nextInt();Qiang q = sb.getQiang ( i );if ( q != null ) {System.out.printf ( "装弹成功!" );sb.R ( q );if ( i == 5 ) {/* 如果选择是手雷 */Fwdh fwdh = (Fwdh) q;   // 强制将父类型转换为子类型fwdh.fwdh(); // 调用投弹!} else if ( i == 6 ) {/* 如果选择是瞄准 */MiaoZhun mz = (MiaoZhun) q;mz.miao();  // 调用瞄准}} elseSystem.out.printf ( "没有该武器,装弹失败!\n" );// 接收值为 true 则默认情况下永远循环System.out.print ( "\n输入 0 结束程序\n<<< " );if ( scInput.nextInt() == 0 )b = false;return b;}
}

测试结果那是相当满意啊:

游戏开始!请选择要装填的武器类型1 >>> 手枪2 >>> 步枪3 >>> 狙枪4 >>> 机枪5 >>> 手雷6 >>> 瞄具
请输入 1~4 编号 <<< 1
装弹成功!为二鞋牌手枪手枪弹药装填十二发!输入 0 结束程序
<<< 1请选择要装填的武器类型1 >>> 手枪2 >>> 步枪3 >>> 狙枪4 >>> 机枪5 >>> 手雷6 >>> 瞄具
请输入 1~4 编号 <<< 5
装弹成功!士兵获取高爆雷1颗!
士兵正在丢手雷5秒后爆炸!输入 0 结束程序
<<< 6请选择要装填的武器类型1 >>> 手枪2 >>> 步枪3 >>> 狙枪4 >>> 机枪5 >>> 手雷6 >>> 瞄具
请输入 1~4 编号 <<< 6
装弹成功!士兵正在安装倍数瞄准镜瞄具一个!
士兵正在使用8倍瞄准镜!输入 0 结束程序
<<< 0
士兵阵亡..游戏结束!

%%%%%

基本类型和引用类型强制转换对比不同

基本数据类型和引用数据类型强制转换的深层认知:

    基本数据类型之间进行强制转换是对被强制转换类型进行值的更改!例如
double a = 5;    // 此时将值 5 变成 5.0 再存储
int a = (int) 521.1314;    // 此时将 521.1314 改成 521 再进行存储而引用数据类型之间强制转换时是还原子类的真实面目 而不是替换子类!例如
父类_1 父对象名_1 = new 子类_1 ( 参数列表 );
子类_1 子对象名_1 = (子类_1) 父对象名_1;    // 正确 还原为真实子类类型
/* 此时如果继续转换就会出问题 */
子类_2 子对象名_2 = (子类_2) 父对象名_1;    // 出现异常 实际上应该相当于基本类型的改变值!

例如我们刚刚的测试是在两个 if 模块中进行转换的 所以没有报错

如果放一起:

Fwdh fwdh = (Fwdh) q;   // 强制将父类型对象枪转换为子类型手雷
fwdh.fwdh();    // 调用子类型对象的投弹方法!
MiaoZhun mz = (MiaoZhun) q;    // 强制将父类型对象枪转换为子类型瞄准
mz.miao();  // 调用瞄准类实例的瞄准方法

执行报错:

异常如下:

游戏开始!请选择要装填的武器类型1 >>> 手枪2 >>> 步枪3 >>> 狙枪4 >>> 机枪5 >>> 手雷6 >>> 瞄具
请输入 1~4 编号 <<< 5
装弹成功!士兵获取高爆雷1颗!
士兵正在丢手雷5秒后爆炸!
Exception in thread "main" java.lang.ClassCastException: mmain.Fwdh cannot be cast to mmain.MiaoZhunat mmain.Main.test(Main.java:43)at mmain.Main.main(Main.java:10)

之前把枪类对象 q 转换为手雷类对象 fwdh 可以访问手雷类独有的投雷方法

但是必须转换为父类指向的真实子类类型手雷类 而不是任意的强制转换!

看后面再转换瞄具类时就出现转换异常 ClassCastException

——————————

instanceof 运算符

在向下转型时 如果没有转换为真实子类类型 就会出现类型转换异常!

那么如何有效地避免这种异常呢?我们可以使用 instanceof 运算符来继续类型的判断!

语法如下:

对象 instanceof 类或接口

该运算符用来判断一个对象是否属于一个类或者实现了一个接口 返回值为 true 或 false

在强制类型转换之前通过 instanceof 运算符检查对象的真实类型再进行相应的强制类型转换就可以避免类型转换异常

从而提高代码的健壮性!

主要类的测试代码修改:

package mmain;public class Main {public static void main(String[] args) {// 第一次测试Qiang bq_1 = new Fwdh( "高爆雷", 5 );   // 子类手雷类型到父类枪类型的转换bq_1.R(); // 装个弹吧if ( bq_1 instanceof Fwdh ) {/* 如果 bq_1 对象等于 Fwdh 手雷类型则执行  */Fwdh fwdh = (Fwdh) bq_1;   // 强制将父类步枪类型转换为子类手雷类型fwdh.fwdh();   // 调用投弹!} else if ( bq_1 instanceof MiaoZhun ) {/* 前面不匹配 再测试 bq_1 对象是否等于 MiaoZhun 瞄准类型 若成立则执行  */MiaoZhun mz = (MiaoZhun) bq_1; // 强制将父类步枪类型转换为子类瞄准类型mz.miao(); // 调用瞄准..}// 第二次测试System.out.println ();Qiang bq_2 = new MiaoZhun( "倍数瞄准镜", 8 );bq_2.R();if ( bq_2 instanceof Fwdh ) {/* 如果是手雷类型便执行 */Fwdh fwdh = (Fwdh) bq_2;fwdh.fwdh();} else if ( bq_2 instanceof MiaoZhun ) {/* 如果是瞄具类型则执行 */MiaoZhun mz = (MiaoZhun) bq_2;mz.miao();}}
}

测试结果:

士兵获取高爆雷1颗!
士兵正在丢手雷5秒后爆炸!士兵正在安装倍数瞄准镜瞄具一个!
士兵正在使用8倍瞄准镜!

可以看到在进行引用类型转换时 先通过 instanceof 运算符进行类型判断再进行相应的强制类型转换

可以有效地避免出现类型转换异常!

    使用 instanceof 运算符时对象的类型必须和 instanceof 的第二个参数所指定的类或接口在继承树上有上下级的关系!否则就会出现编译错误!例如跟字符串类型比较就会报错:
枪类 instanceof String此外 instanceof 通常和强制类型转换结合使用!

12.0_[Java 多态]-多态/子类父类互转/基本引用类型互转/ instanceof 运算符相关推荐

  1. java的知识点11——面向对象的三大特征之一继承、instanceof 运算符、方法的重写override、Object类基本特性、toString方法

    面向对象的三大特征:继承.封装.多态 继承的实现 继承让我们更加容易实现类的扩展.子类是父类的扩展 使用extends实现继承 package cn.sxt;public class Test {pu ...

  2. Java入门——多态详解

    关于Java语言中的多态语法机制:[只是多态的基础语法,具体应用后面说] Animal.Cat.Brid三个类的关系 Cat继承Animal Brid继承Animal Cat和Brid之间没有任何继承 ...

  3. Java 8中的instanceof运算符和访客模式替换

    我有一个梦想,不再需要操作员和垂头丧气的instanceof ,却没有访客模式的笨拙和冗长. 所以我想出了以下DSL语法: Object msg = //...whenTypeOf(msg).is(D ...

  4. oracle无效的关系运算符_每日一课 | Java 8中的instanceof运算符和访客模式替换

    我有一个梦想,不再需要操作员和垂头丧气的instanceof ,却没有访客模式的笨拙和冗长.所以我想出了以下DSL语法: Object msg = //... whenTypeOf(msg).     ...

  5. java 访客模式,每日一课 | Java 8中的instanceof运算符和访客模式替换

    每日一课 | Java 8中的instanceof运算符和访客模式替换 每日一课 | Java 8中的instanceof运算符和访客模式替换 我有一个梦想,不再需要操作员和垂头丧气的instance ...

  6. 学习-Java继承和多态之子类继承性

    第1关:学习-Java继承和多态之子类继承性 任务描述 相关知识 编程要求 测试说明 任务描述 本关任务:定义一个 Dog 类,继承 Animal 类(Animal 类已经定义),定义自己的性别属性, ...

  7. 多态是什么 父类如何调用子类的方法(美团面试)

    这道题是来自牛客网的一位小哥在2019的最后一天面试系统开发工程师的补招的一个面试题目, 在Java面试中,多态是一个被问到的频率很高的一个概念. 面试官:什么是多态呢? 猪队友:多种形态,气体,液体 ...

  8. 学习-Java继承和多态之子类对象特点

    第1关:学习-Java继承和多态之子类对象特点 任务描述 相关知识 子类对象的特点 instanceof 运算符 编程要求 测试说明 任务描述 本关任务:使用 instanceof 运算符判断所指对象 ...

  9. java中多态_java之多态

    1.多态的概述:是面向对象的三大特性之一,封装.继承.多态. ①一个具体的对象有多种形态,老虎既属于猫科动物(因为子父类是相对的,所以猫科动物也可以看做子类),又属于哺乳动物,所以老虎既可以拥有猫科动 ...

最新文章

  1. Rocksdb 的 BlobDB key-value 分离存储插件
  2. Windows Phone 8初学者开发—第19部分:设置RecordAudio.xaml页面
  3. asp.net服务器控件与html服务器控件的区别
  4. 2017年 JavaScript 框架回顾 -- 前端框架
  5. LinkedList阅读
  6. 我是如何学习写一个操作系统(七):进程的同步与信号量
  7. ABP vNext微服务架构详细教程——基础服务层
  8. 3皮卡丘眨眼代码_活见久,皮卡丘居然是一门编程语言
  9. 改变centos系统的时区
  10. Linq在路上(序)
  11. 直播实时转播软件_多群转播神器——转播小助手
  12. 覆盖Dispatch响应消息
  13. java arraylist_Java 集合框架之 ArrayList 源码图示法简要剖析
  14. 安卓微信本地数据库解密
  15. python如何打开txt文件、并算词频_python读取word文本进行词频统计
  16. html文档成品,HTML成品代码
  17. 洛谷 P2689 东南西北
  18. 易基因|3文一览:ChIP-seq技术在植物转录因子结合位点中的研究(茄子+玉米+水稻)
  19. PCAT 点云标注软件
  20. 8天掌握EF的Code First开发系列之动手写第一个Code First应用

热门文章

  1. DW1000学习之路(三)--------DW1000的中断处理问题
  2. 试算平衡表示例图_试算平衡表的编制 试算平衡表示例图
  3. 2019年中科院信工所夏令营考核内容
  4. JS生成随机颜色(rgb)
  5. 导出excel.支持在线打开保存
  6. 与浏览网站的访客直接进行QQ对话
  7. Vue2.0源码解析 - 知其然知其所以然之Vue.use
  8. (二)机器学习的流程概述,线性规划,图像分类
  9. Android桌面老是跳广告,电脑桌面老是弹出广告怎么办?简单3步轻松屏蔽!
  10. windows无法连接到打印机,错误为0x0000000b,无效句柄,解决办法。