Java转型(向上转型和向下转型)

Java编程中经常碰到类型转换,对象类型转换主要包括向上转型和向下转型。

5.13.1 向上转型

我们在现实中常常这样说:这个人会唱歌。在这里,我们并不关心这个人是黑人还是白人,是成人还是小孩,也就是说我们更倾向于使用抽象概念“人”。再例如,麻雀是鸟类的一种(鸟类的子类),而鸟类则是动物中的一种(动物的子类)。我们现实中也经常这样说:麻雀是鸟。这两种说法实际上就是所谓的向上转型,通俗地说就是子类转型成父类。这也符合Java提倡的面向抽象编程思想。来看下面的代码:

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");

}

}

CRTMonitor、PlasmaMonitor类的修改方法与LCDMonitor类似,而MyMonitor可以不不作任何修改。

可以看出,向上转型体现了类的多态性,增强了程序的简洁性。

5.13.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

其实黑体部分的向下转型代码后的注释已经提示你将发生运行时错误。为什么前一句向下转型代码可以,而后一句代码却出错?这是因为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异常了。

时间: 2024-12-26 13:28:59

Java转型(向上转型和向下转型)的相关文章

一个向上转型的指针强制向下转型

场景描述:实例化子类,然后将地址传递给父类的指针,父类的指针在得到子类的实例地址之后,重新强制转化成子类的指针,通过static_cast成功实现了转型. class CFather{ public:     void Display()     {         cout<<"Father display"<<endl;     } }; class CSon:public CFather { public:      void Display()     

java(向上向下转型)

在Java编程中经常碰到类型转换,对象类型转换主要包括向上转型和向下转型. 5.13.1 向上转型 我们在现实中常常这样说:这个人会唱歌.在这里,我们并不关心这个人是黑人还是白人,是成人还是小孩,也就是说我们更倾向于使用抽象概念"人".再例如,麻雀是鸟类的一种(鸟类的子类),而鸟类则是动物中的一种(动物的子类).我们现实中也经常这样说:麻雀是鸟.这两种说法实际上就是所谓的向上转型,通俗地说就是子类转型成父类.这也符合Java提倡的面向抽象编程思想.来看下面的代码: package a.

java 向上转型和向下转型

学习向上转型和向下转型怎么用没多难,但是为什么那样用,我搞了很多次没弄明白.没弄明白的原因是平时学习时之看例子,而例子一般都比较简单,没有对象之间的调用,一般就是一个对象调用自己的方法. 首先看下怎么用转型. 要转型,首先要有继承.继承是面向对象语言中一个代码复用的机制,简单说就是子类继承了父类中的非私有属性和可以继承的方法,然后子类可以继续扩展自己的属性及方法. 向上转型:子类对象转为父类,父类可以是接口.公式:Father f = new Son();Father是父类或接口,son是子类.

java的向上转型与向下转型

刚开始接触java转型,虽然现在还不知道为什么要转型,但是先强记下语法吧 向上转型: 首先要有一个父类,一个子类, Person p=new Person(); p=new Student(); OK,这就是向上转型,可以简化成:Person p=new Student(); 1)   p是Person的引用,指向Student的对象,p不是对象; 2)   p只能调用父类中有的成员变量与成员函数,子类中新有的方法与变量p不能使用,而执行的主体是子类的主体. 例如 class Person{ v

JavaSE(五)JAVA对象向上转型和向下转型

今天做了一个测试的题目,发现自己还是很多问题没有静下心来做.很多问题是可以自己解决的但是自己一是没有读清题意,二是自己心里太急躁了.所以这个要自己应以为鉴! 对象的转型问题其实并不复杂,我们记住一句话:"父类引用指向子类对象". java中对象的转型分为向上转型和向下转型 一.对象的向上转型 1.1.定义 子类引用的对象转换为父类类型称为向上转型.通俗地说就是是将子类对象转为父类对象.此处父类对象可以是接口 1.2.解释 比如说我有两个类,一个是父类Animal,另一个是Bird类为子

java中的向上转型与向下转型

以前学Javase时就专门注意过这个问题,现在到了现在又犯了这个错误,这个错误让我排查了好久 1 : 向上转型:大体可以理解为子类转换成父类,例子优先还是: 1 public class Animal { 2 public void eat(){ 3 System.out.println("animal eatting..."); 4 } 5 } 7 public class Cat extends Animal{ 9 public void eat(){ 11 System.out.

向上与向下转型

向下转型 在向下转型过程中,分为两种情况: 如果父类引用的对象如果引用的是指向的子类对象,那么在向下转型的过程中是安全的.也就是编译是不会出错误的. 如果父类引用的对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现java.lang.ClassCastException错误.它可以instanceof来避免出错此类错误. 1 Father fh=new Father(); 2 if(fh instanceof Son) 3 { 4 Son son =(Son)fh;

从向上向下转型到----抽象类接口(一)

对象的多态性-向上向下转型 向上转型:子类对象变为父类对象,格式:父类 父类对象 = 子类实例,自动转换; 向下转型:父类对象变为子类对象,格式:子类 子类对象 = (子类) 父类实例,强制转换; 注意:对象的多态性和方法复写是联系在一起的 向上转型: class A{ public void print(){ System.out.println("a") } } class B extends A{ public void print(){ System.out.println(&

java上转型和下转型(对象的多态性)

/*上转型和下转型(对象的多态性) *上转型:是子类对象由父类引用,格式:parent p=new son *也就是说,想要上转型的前提必须是有继承关系的两个类. *在调用方法的时候,上转型对象只能调用父类中有的方法,如果调用子类的方法则会报错 *下转型:是父类向下强制转换到子类对象 *前提是该父类对象必须是经过上转型的对象. * *代码示例:*/ 1 abstract class Parent{ 2 abstract void grow(); 3 } 4 class Son extends P