woaidongmao

文章均收录自他人博客,但不喜标题前加-[转贴],因其丑陋,见谅!~
随笔 - 1469, 文章 - 0, 评论 - 661, 引用 - 0
数据加载中……

Java中的向上转型和向下转型

class Useful

{
int value = 20;
public void f() {System.out.println("f() in the Useful class");}
public void g() {System.out.println("g() in the Useful class");}
}

class MoreUseful extends Useful {
int value = 21;
public void f() {System.out.println("f() in the MoreUseful class");}
public void g() {System.out.println("g() in the MoreUseful class");}
public void u() {System.out.println("u() in the MoreUseful class");}
public void v() {}
public void w() {}
}

class MoreUseful2 extends Useful {
int value = 21;
public void f() {System.out.println("f() in the MoreUseful2 class");}
public void g() {System.out.println("g() in the MoreUseful2 class");}
public void u() {System.out.println("u() in the MoreUseful2 class");}
public void v() {}
public void w() {}
}


class ExtendsMoreUseful2 extends MoreUseful2 {
int value = 22;
public void f() {System.out.println("f() in the ExtendsMoreUseful2 class");}
public void g() {System.out.println("g() in the ExtendsMoreUseful2 class");}
public void u() {System.out.println("u() in the ExtendsMoreUseful2 class");}
public void v() {}
public void w() {}
}

public class RTTI {
public static void main(String[] args) {

//Useful useful = new MoreUseful();
//useful.u();   //
这是错误的,u()方法没有在useful类型中调用。

         Useful[] x =
         {
          new Useful(),
          new MoreUseful(),
          new MoreUseful2(),
          new ExtendsMoreUseful2()
          };
//
声明一个变量数组,保存每个Useful对象的引用,
             //
那么每一个Useful对象就会自动向上转型为Useful

for(int i=0;i<x.length;i++)
{
if(x[i] instanceof MoreUseful2) //
判断instanceof左边的对象是否是右边的类的实例。
{
   MoreUseful2 moreuseful2 = (MoreUseful2)x[i];//
向下转型(具体解释见下面的分析)
   moreuseful2.u();
}

x[i].g(); //这是动态绑定,将方法的调用和方法主体关联起来就是动态绑定。

}

运行结果:

g() in the Useful class        // 由于x[0].g()这一句中调用g()方法实际的对象类型是

                                            // 基类Useful类型,故将调用基类中的f()方法。(没有转型)
                             

g() in the MoreUseful class      // 由于x[1].g()这一句中调用g()方法实际的对象类型是

                                                   //子类Moreuseful类型,故将调用子类Moreuseful

                                                  //   覆盖父 类的g()方法。(向上转型)
                                  

u() in the MoreUseful2 class        // 由于x[2]MoreUseful2类型,故可以对其向下转型调

                                                        // MoreUseful2中的扩展方法u()。(向下转型)

g() in the MoreUseful2 class        // x[2].g()这一句中调用g()方法实际的对象类型是子

                                                   // Moreuseful类型,故将调用子类Moreuseful
                                                       //  
覆盖父类的g()方法。(向上转型)

u() in the ExtendsMoreUseful2 class     // 由于x[3]ExtendMoreUseful2类型,

                                   // 它是MoreUseful2的子类,存在is-a关系,故可以对其向下转

                          // ,将调ExtendMoreUseful2中的扩展的方法u()。(向下转型)

g() in the ExtendsMoreUseful2 class     // x[3].g()这一句中调用g()方法实际的对象类型

                                                                   //是子类ExtendMoreuseful类型故将调用
                                    //
子类ExtendMoreuseful中覆盖父类的g()方法。(向上转型)


分析和结论:

(一)向上转型

1)定义: 把对某个对象的引用视为对其基类引用的做法被称为向上转型
    
这主要是由于子类的对象可以看成是基类的对象这原因而得来的,也就是具有is-a关系。

比如:
     Useful useful = new MoreUseful();//
右边是一个子类的对象,而左边是一个父类类型
                                      //
的变量,指向右边的子类对象。

2)基类可以接收发给导出类的任何消息,因为二者有完全相同的接口,我们只需要

从导出类向上转型,永远不需要知道正在处理的对象的确切类型,这也就是多态性决

定的。利用多态性,具有同样方法名和方法特征的方法根据调用方法的对象的类型,

可以产生不同的动作,这极大地增加了程序员的表达能力。


    
回头再看一看上面这个例子中的一段for循环代码,

for(int i=0;i<x.length;i++)
{
if(x[i] instanceof MoreUseful2)   //
判断instanceof左边的对象是否是右边的类的实例。
{
MoreUseful2 moreuseful2 = (MoreUseful2)x[i]; //
向下转型(具体解释见下面的分析)
moreuseful2.u();
}

x[i].g(); //动态绑定

}
    
主要看x[i].g();这一句话,现在我们还不知道x[i]这个到底是指代哪一个Useful对象,

在这种情况下,编译器是怎么知道调用哪个方法的呢?这是一个动态绑定的问题,见

下面。

(二)动态绑定

1)定义:将方法的调用和方法主体关联起来就是动态绑定。

比如:x[i].g();这就是一个动态绑定,x[i]是一个对象类型,g()是一个不知道是属于

哪个对象的方法,将这两个两个联合在一起,就是一个绑定。

2要注意:Java中除了staticfinal方法(private方法属于final方法,因为fianl方法

不可以覆盖,static方法是一个全局方法,属于所有类共享,不在多态范围内)之外,

其他所有的方法都是动态绑定,这就意味着在通常情况下,我们不必判定是否应该进

行动态绑定,因为这个会自动发生。

3)接着上面的答复。编译器是怎么知道调用哪个方法的呢?

主要还是x[i].g();这一句话的作用,x[i]在调用方法的时候,会调用实际的方法,这

个实际的方法由所引用的对象的类型决定。那么调用的实际方法可能是父类中没有被

子类覆盖的方法,也可能是子类中覆盖父类的方法,主要看调用这个方法的实际的对

象类型是哪一个。


(三)向下转型

既然有向上转型,那么有没有向下转型呢?

答:有

1)概述

继承可以确保所有的子类类具有基类的接口,且绝对不会少。那么子类除了有父类的

方法,也可以有自己的额外的新方法(这些方法是基类所没有的),那么一旦向上转

型,就不能调用子类中的新方法,那么能不能用一种方式调用这些新方法呢?当然有

了,这时候就需要向下转型。

2)向下转型

将超类的引用强制转换为子类类型就叫做向下转型。

注意:将超类的引用赋给为子类类型的变量(没有进行显示地强制转换)是一个编译

错误。

例子:

还是上面的for循环代码

for(int i=0;i<x.length;i++)
{
if(x[i] instanceof MoreUseful2) //    
判断instanceof左边的对象是否是右边的类的实例。
{
MoreUseful2 moreuseful2 = (MoreUseful2)x[i]; //
向下转型
moreuseful2.u();
}

x[i].g();

}


分析:x[i]可以代表具体的Useful对象类型,当它是MoreUseful2ExtendsMoreUseful2

对象类型时,就可以调用该对象的额外方法u(),v(),w()也就是当对象x[i]Moreusful

象存在is-a关系时,才可以进行向下转型,如果要转换的对象类型与指定的对象类型不

存在is-a关系时,会产生一个ClassCastException异常。

总之:

向下转型时,对象只能强制转换为其本身类型或者其超类类型。比如,

x[i]ExtendsMoreUseful2对象时,可以把他转换为其本身ExtendsMoreUseful2对象类

型,也可以把它转换为其基类MoreUseful2类型。但是在编译时候还不知道这个x[i]是代

表那个具体对象类型只知道这个x[i]是基类类型引用,所以要用这样的形式" (想要要得

到的类型)x[i] " 进行转换。x[i]在这里是就我这个例子来说明的,你也可以使用其它的

英文代替,其意义是一切符合规定的需要被转换的对象。

下面还有个关于向上转型和向下转型的例子,

abstract class ClassAbstract1{}
class ClassDerived1 extends ClassAbstract1
{
public void play1()
{
   System.out.println("play1() is in the ClassDerived1");
}
}
abstract class ClassAbstract2{public abstract void play2();}
class ClassDerived2 extends ClassAbstract2
{
public void play2()
{
   System.out.println("play2() is in the ClassDerived2");
}
}


public class E14_UnCast {

public static void playDemo1(ClassAbstract1 ObjectParameter)
{
   ((ClassDerived1)ObjectParameter).play1();//
向下转型,可以调用导出类中的扩展方法
}

public static void playDemo2(ClassAbstract2 ObjectParameter)
{
   ObjectParameter.play2();//
向上转型,可以调用导出类中的覆盖方法
}

/**
* @param args
*/
public static void main(String[] args) {
   // TODO Auto-generated method stub
   ClassAbstract1 classabstract = new ClassDerived1();
   playDemo1(classabstract);
   ClassAbstract2 classabstract2 = new ClassDerived2();
   playDemo2(classabstract2);

}

}


运行结果:
play1() is in the ClassDerived1
play2() is in the ClassDerived2

 

 

posted on 2009-07-27 13:00 肥仔 阅读(1046) 评论(0)  编辑 收藏 引用 所属分类: Web-后台


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理