摘要:向上转型子类转型成父类举例的子类覆盖父类方法类定义了自己的新方法类向上转型如果运行,输出的是还是不是你原来预期的,而是。不过,由于向上转型,对象会遗失和父类不同的方法,例如。其实,不仅仅如此,向上转型还可以减轻编程工作量。
1 向上转型(子类转型成父类)
举例:
package a.b; public class A { public void a1() { System.out.println("Superclass"); } } A的子类B: package a.b; public class B extends A { public void a1() { System.out.println("Childrenclass"); //覆盖父类方法 } public void b1(){} //B类定义了自己的新方法 } C类: package a.b; public class C { public static void main(String[] args) { A a = new B(); //向上转型 a.a1(); } }
如果运行C,输出的是Superclass 还是Childrenclass?不是你原来预期的Superclass,而是Childrenclass。这是因为a实际上指向的是一个子类对象。当然,你不用担心,Java虚拟机会自动准确地识别出究竟该调用哪个具体的方法。不过,由于向上转型,a对象会遗失和父类不同的方法,例如b1()。有人可能会提出疑问:这不是多此一举吗?我们完全可以这样写:
B a = new B();
a.a1();
确实如此!但这样就丧失了面向抽象的编程特色,降低了可扩展性。其实,不仅仅如此,向上转型还可以减轻编程工作量。来看下面的显示器类Monitor:
package a.b; public class Monitor{ public void displayText() {} public void displayGraphics() {} } 液晶显示器类LCDMonitor是Monitor的子类: package a.b; public class LCDMonitor extends Monitor { public void displayText() { System.out.println("LCD display text"); } public void displayGraphics() { System.out.println("LCD display graphics"); } } 阴极射线管显示器类CRTMonitor自然也是Monitor的子类: package a.b; public class CRTMonitor extends Monitor { public void displayText() { System.out.println("CRT display text"); } public void displayGraphics() { System.out.println("CRT display graphics"); } } 等离子显示器PlasmaMonitor也是Monitor的子类: package a.b; public class PlasmaMonitor extends Monitor { public void displayText() { System.out.println("Plasma display text"); } public void displayGraphics() { System.out.println("Plasma display graphics"); } } 现在有一个MyMonitor类。假设没有向上转型,MyMonitor类代码如下: package a.b; public class MyMonitor { public static void main(String[] args) { run(new LCDMonitor()); run(new CRTMonitor()); run(new PlasmaMonitor()); } public static void run(LCDMonitor monitor) { monitor.displayText(); monitor.displayGraphics(); } public static void run(CRTMonitor monitor) { monitor.displayText(); monitor.displayGraphics(); } public static void run(PlasmaMonitor monitor) { monitor.displayText(); monitor.displayGraphics(); } } 可能你已经意识到上述代码有很多重复代码,而且也不易维护。有了向上转型,代码可以更为简洁: package a.b; public class MyMonitor { public static void main(String[] args) { run(new LCDMonitor()); //向上转型 run(new CRTMonitor()); //向上转型 run(new PlasmaMonitor()); //向上转型 } public static void run(Monitor monitor) { //父类实例作为参数 monitor.displayText(); monitor.displayGraphics(); } } 我们也可以采用接口的方式,例如: package a.b; public interface Monitor { abstract void displayText(); abstract void displayGraphics(); } 将液晶显示器类LCDMonitor稍作修改: package a.b; public class LCDMonitor implements Monitor { public void displayText() { System.out.println("LCD display text"); } public void displayGraphics() { System.out.println("LCD display graphics"); } }
2 向下转型(父类转型成子类)
A类: package a.b; public class A { void aMthod() { System.out.println("A method"); } } A的子类B: package a.b; public class B extends A { void bMethod1() { System.out.println("B method 1"); } void bMethod2() { System.out.println("B method 2"); } } C类: package a.b; public class C { public static void main(String[] args) { A a1 = new B(); // 向上转型 a1.aMthod(); // 调用父类aMthod(),a1遗失B类方法bMethod1()、bMethod2() B b1 = (B) a1; // 向下转型,编译无错误,运行时无错误 b1.aMthod(); // 调用父类A方法 b1.bMethod1(); // 调用B类方法 b1.bMethod2(); // 调用B类方法 A a2 = new A(); B b2 = (B) a2; // 向下转型,编译无错误,运行时将出错 b2.aMthod(); b2.bMethod1(); b2.bMethod2(); } } 从上面的代码我们可以得出这样一个结论:向下转型需要使用强制转换。运行C程序,控制台将输出: Exception in thread "main" java.lang.ClassCastException: a.b.A cannot be cast to a.b.B at a.b.C.main(C.java:14) A method A method B method 1 B method 2
其实B b2 = (B) a2处的向下转型代码后的注释已经提示你将发生运行时错误。为什么前一句向下转型代码可以,而后一句代码却出错?这是因为a1指向一个子类B的对象,所以子类B的实例对象b1当然也可以指向a1。而a2是一个父类对象,子类对象b2不能指向父类对象a2。那么如何避免在执行向下转型时发生运行时ClassCastException异常?使用5.7.7节学过的instanceof就可以了。我们修改一下C类的代码:
A a2 = new A(); if (a2 instanceof B) { B b2 = (B) a2; b2.aMthod(); b2.bMethod1(); b2.bMethod2(); }
这样处理后,就不用担心类型转换时发生ClassCastException异常了。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/73765.html
摘要:所以静态方法不能被覆盖。虽然就算你重写静态方法,编译器也不会报错。也就是说,如果你试图重写静态方法,不会阻止你这么做,但你却得不到预期的结果重写仅对非静态方法有用。我们应该直接使用类名来访问静态方法,而不要使用对象引用来访问。 重写/重载 重写指的是根据运行时对象的类型来决定调用哪个方法,而不是根据编译时的类型。所以静态方法不能被覆盖。 (如果从重写方法会有什么特点来看,我们是不能...
摘要:多态访问成员变量的两种方式直接通过对象名称访问成员变量看等号左边是谁,优先用谁,没有则向上找。只用于成员方法,不适用于成员变量。 多态性: 是对对象来说的。extends或implements是多态性的前提。 经理类继承雇员类。小明是一个经理对象,这个对象既有经理形态,也有雇员形态。一个对象有多种形态,这就是对象的多态性。 多态性格式:父类引用指向子类对象 格式:父类名称 对象名 = ...
摘要:引用数据类型转换由的继承和向上转型,子类可以很自然地转换为父类对象,即父类类型可以直接引用子类对象,但是子类类型不能直接引用父类对象,需要进行强制转换。但是将功能较弱的类型父类强制转功能较强的对象子类时,就不一定可以行了。 1、引用数据类型转换: 由java的继承和向上转型,子类可以很自然地转换为父类对象,即父类类型可以直接引用子类对象,但是子类类型不能直接引用父类对象,需要进行强制转...
阅读 2812·2021-11-19 11:35
阅读 2583·2021-11-02 14:40
阅读 1397·2021-09-04 16:48
阅读 3012·2019-08-30 15:55
阅读 1758·2019-08-30 13:11
阅读 1957·2019-08-29 11:12
阅读 1088·2019-08-27 10:52
阅读 3158·2019-08-26 18:36