12.0

12.0

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

目录

多态

什么是多态

为什么使用多态

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

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

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

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

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

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 通常和强制类型转换结合使用!

发布者:admin,转转请注明出处:http://www.yc00.com/news/1692500457a600731.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信