`

java实例多态

阅读更多
通过实例说明Java中的多态
Java中的多态允许父类指针指向子类实例。如:Father obj=new Child();(其中Child是Father的子类)。这样就产生了一个问题——

使用这个父类型的指针访问类的属性或方法时,如果父类和子类都有这个名称的属性或方法,哪一个属性或方法会被调用呢?

最好的办法是实验:
class Father
{
    int r;
    Father()
    {
        r=4;
    }
    void printname()
    {
        System.out.println("I'm father");
    }
}
class Child extends Father
{
    int r;
    Child()
    {
        r=5;
    }
    void printname()
    {
        System.out.println("I'm Child");
    }
}
public class Test
{
    public static void main(String[] args)
    {
        Father obj=new Child();
        System.out.println(obj.r);
        obj.printname();
    }
}

结果输出:

4
I'm Child


实验证明。属性会访问父类的。方法会访问子类的。

支持将Child型的实例放在Father型的变量里,这就是多态了。

不要以为Father obj=new Child();这条语句一定会让obj.printname()指向Chlid定义的printname()。实际上,如果你把Father类中的printname()方法删除,这个程序将编译失败。因为Father中的并没有定义printname()这个函数。多态是晚绑定*(见本文最后的资料)的,在Father obj=new Child();这个语句中,如果Father中没有printname()这个函数,就不会为obj建立一个用于调用printname()函数的指针。所以调用obj.printname()会出错。如果Father中有这个函数。指向printname()函数的指针会被创建。在调用obj.printname()时,不会出错,而且,因为obj指向的是new Child(),是个Chld类的实例。所以调用obj.printname()时调用了Child类中定义的printname()。这就是方法的动态绑定。

那么,刚才说到把Father类中的printname()方法删掉后,obj将无法调用Child类中的printname(),因为obj.printname()会编译失败。那么如果我就是需要调用要怎么办呢?其实虽然obj是Father类型的,但是它指向的是一个Child类的实例。那么可以将obj强制类型转换为Child。再调用printname()方法就可以了。

在上面程序中,把Father类中的printname()方法整个删掉,再将obj.printname() 改成 ((Child)obj).printname()后,编译成功,结果输出:

4
I'm Child


两次输出的结果都是I'm Child。

那么如何可以运行Child类中的printname()来输出“I'm Father”呢?

其实只需要将Father obj=new Child();改成Father obj=new Father();就可以了,呵呵。另一个办法就是将Child类中定义的printname()整个删掉。为什么这样可以成功呢?自己想想,嘿嘿。最后会有个这样的思考题。



看到这儿你可能早就想问了:

为什么obj.r是4?为什么不是5?

呵呵。其实很简单。Java中的多态仅为方法而言,成员变量还是使用的父类的成员变量。也就是说,因为“Father obj =……”,所以obj是Father类型的,所以obj里面的r是Father里面的r,所以输出obj.r就是4了。

你又想问:

那么5去哪了?new Child()的时候,不是会把5放到Child的r中吗?

实际上5还是有的。只是obj.r是4而已。想访问Child中的r,把5读出来,可以这样写:

((Child)obj).r



就是把obj由Father型强制转换成了Child型。


OK,方法和属性在多态中是什么样的你都清楚了。现在做个题测试一下吧:

这是J@Whiz1.4的一道题:
class Base {
        int i = 99;
        public void amethod() {
                System.out.println("Base.amethod()");
        }
        Base() {
                amethod();
        }
}
public class Derived extends Base {
        int i = -1;
        public static void main(String argv[]) {
                Base b = new Derived();
                System.out.println(b.i);
                b.amethod();
       }
       public void amethod() {
                System.out.println("Derived.amethod()");
       }
}


会输出什么?

先想想,再看答案:



答案:
========================
Derived.amethod()
99
Derived.amethod()
========================
讲解:

这个程序的执行过程是这样的:

第一行:Base b=new Derived();

执行这一行语句的过程中,要构造Derived这个类,而它有父类Base,所以先构造Base类。构造Base类的默认构造函数有定义。内容是执行amethod()方法。

实际上,Base类构造方法中的执行amethod(),相当于执行this.amethod(),在这个程序中,就相当于执行b.amethod()。而b是Base类型的,指向了Derived类的实例的指针。所以跟据上面我们的总结,实际上执行的是Derived类的amethod()函数。所以,第一行“Base b=new Derived();”执行完,输出"Derived.amethod()"。

第二行:System.out.println(b.i);

这个很简单,成员变量,不考虑多不多态,只看它定义时前面的类型。这个程序中是Base b,所以b.i就是Base类中的i。输出99

第三行:b.amethod();

调用Derived类中的amethod()方法。

其实这行就是迷惑你的,如果没有这一行。你可能会警觉起来——咦?为什么这儿定义一个amethod()呢?没有地方调用它啊?

有了这行代码,就会使你放松警惕。觉得,啊。定义了这个是用来让b.amethod();调用的。




留个思考题,也很重要的,一定要试试。

就是——如果在Derived类中。把public void amethod()这整个函数去除掉。程序又会输出什么呢?





资料:

http://blog.csdn.net/yizhu2000/archive/2007/07/12/1686634.aspx

摘抄:

绑定:在对象和其类型间建立关联的过程

早绑定:指在对象申明的时候就和他的类型建立了关联

晚绑定:是指我们的代码在运行时再检查对象是否提供了我们所需要的方法和属性


http://bbs.chinajavaworld.com/thread.jspa?threadID=636061&start=0&tstart=0

这是个很有趣的讨论。里有对本文第二个程序的讨论。

不过,里面写的那个接口的程序有点问题,我整理了一下,并作了注解:

interface CA {
    public void func();
}

class CB implements CA {
    public void func(){
        System.out.println("Good");
    }
}

class CC {
    public CA createCA() {  //多态的方法,CA是CB的父类
        return new CB();
    }
}

public class Headache
{
    public static void main(String[] args) {
        CC c = new CC();
        c.createCA().func(); //多态,c.createCA()返回CA的型的引用
        //(这个CA的引用中,指向的其实是CB的实例)
        //.func()执行的是子类CB中定义的func()
        CA ca = c.createCA();
        ca.func();   //和c.createCA().func()完全一样。ca就是c.createCA()
        Object caa=c.createCA(); //多态
        ((CA)caa).func(); //Object转换后,还是多态,执行的是CA子类CB里定义的func
        //(实现接口可以看作是继承,可以实现多个接口,就实现了C++中的多继承)
        CB cb = (CB)ca;  //转换成要调用它方法的子类
        cb.func();
    }
}

张旋(zxsoft)
如对本文有什么疑问,请在下面写下留言,谢谢
分享到:
评论

相关推荐

    Java 继承 多态方面的实例源码.rar

    Java 继承 多态方面的实例源码,内容方面涉及对象类Object和它的toString()方法、多态性、动态绑定和一般程序设计、数组线性表ArrayList类、final类、方法和变量、数据域和静态方法的隐藏等。。。

    Java中多态的具体应用代码

    Java开发之多态的具体应用,包含多态应用的实例和相应实例的代码。

    java 多态实例

    一个简单的多态实例,包含interface,abstract class 以及两种排序方式

    java的多态扩展性

    java教学视频,讲解了多态的扩展性、转型、成员特点、主板实例、object类等

    java中多态的使用实例

    主要java中接口,继承以及抽象等基础内容的实例,实初学者能刚好的理会多态的具体含义

    java基础 继承和多态实例

    //练习: //1.做一个教师类Teacher,有属性:1.教师号,2教师姓名, //3教师工资(基本工资,课时费,课时数)。 //有方法:1.输出教师所有信息,2.... //2....//(1)该类有以下属性:学校编号:schId, ...

    java 多态.docx

    多态是同一个行为具有多个不同表现形式或形态的...多态就是同一个接口,使用不同的实例而执行不同操作,如图所示: 多态性是对象多种表现形式的体现。例如,针对不同对象,计算机对按下 F1 键这个动作的响应是不同的:

    java 接口 类 继承 多态的简单实例

    实现重载(overload)和重写(override) 调用中用到多态,向上转换,强制转换 所有被创建的类,都各自创建两个实现接口 最底层的类中创建内部类,并在外部类中调用内部类的方法

    关于Java多态实例共3页.pdf.zip

    关于Java多态实例共3页.pdf.zip

    java多态的讲解

    用代码实例和注释向你讲述什么是多态,实例更容易理解

    Java封装继承多态实例以及文件流操作

    Java封装继承多态实例以及文件流操作,自己整理的东西,用了单态模式实现了多态,并且贯彻了OOP思想,用到了文件流的写入与读取,希望对大家有帮助

    java 继承与多态应用 输出员工信息 代码实例

    java 继承与多态应用 输出员工信息java 继承与多态应用 输出员工信息 代码实例

    java多态性练习

    关于java多态性和abstract修饰的使用 一个具体的实例 简单易懂

    java继承及多态概念PPT

    本PPT对java继承的基本概念,语法及应用进行了讲解。在继承的基础上进一步讲解了由继承引出的方法重写及上塑造性,最后引出多态的概念以及相关代码实例

    Java多态的深度剖析

    帮助你完全理解java多态的含义并附实例代码

    java多态的实现

    本实例详细阐述java平台下如何实现多态,多态有什么特征,以及需要注意的地方,小例子。

    Java中的多态用法实例分析

    主要介绍了Java中的多态用法,较为详细的分析了java中多态的概念与相关的实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下

    java 多态实例代码

    主要介绍了java 多态实例代码,具有一定借鉴价值,需要的朋友可以参考下

    《java面向对象程序设计-继承和多态》教案.doc

    多态性是不同的实例对象以不同的方式对相同的信息作出不同的表现 访问修饰符用于确定访问类成员的方式 Java 常用修饰符有 static、final、abstract 接口是Java编程一项重要的技术,同过它可以实现多态,同时它也弥补...

Global site tag (gtag.js) - Google Analytics