Java向上转型和向下转型

60次阅读

共计 3388 个字符,预计需要花费 9 分钟才能阅读完成。

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 异常了。

正文完
 0