`

java中的多态性 体现

    博客分类:
  • java
阅读更多

一、基本概念

多态性:发送消息给某个对象,让该对象自行决定响应何种行为。
通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。

java 的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

1. 如果a是类A的一个引用,那么,a可以指向类A的一个实例,或者说指向类A的一个子类。
2. 如果a是接口A的一个引用,那么,a必须指向实现了接口A的一个类的实例。


二、Java多态性实现机制

SUN目前的JVM实现机制,类实例的引用就是指向一个句柄(handle)的指针,这个句柄是一对指针:
一个指针指向一张表格,实际上这个表格也有两个指针(一个指针指向一个包含了对象的方法表,另外一个指向类对象,表明该对象所属的类型);
另一个指针指向一块从java堆中为分配出来内存空间。

The Java Virtual Machine does not require any particular internal structure for objects. In Sun 's current implementation of the Java Virtual Machine, a reference to a class instance is a pointer to a handle that is itself a pair of pointers: one to a table containing the methods of the object and a pointer to the Class object that represents the type of the object, and the other to the memory allocated from the Java heap for the object data. (jvm规范中关于对象内存布局的说明)


三、总结

1、通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。

DerivedC c2=new DerivedC();
BaseClass a1= c2; //BaseClass 基类,DerivedC是继承自BaseClass的子类
a1.play(); //play()在BaseClass,DerivedC中均有定义,即子类覆写了该方法

分析:
* 为什么子类的类型的对象实例可以覆给超类引用?
自动实现向上转型。通过该语句,编译器自动将子类实例向上移动,成为通用类型BaseClass;
* a.play()将执行子类还是父类定义的方法?
子类的。在运行时期,将根据a这个对象引用实际的类型来获取对应的方法。所以才有多态性。一个基类的对象引用,被赋予不同的子类对象引用,执行该方法时,将表现出不同的行为。

在a1=c2的时候,仍然是存在两个句柄,a1和c2,但是a1和c2拥有同一块数据内存块和不同的函数表。

2、不能把父类对象引用赋给子类对象引用变量

BaseClass a2=new BaseClass();
DerivedC c1=a2;//出错

在java里面,向上转型是自动进行的,但是向下转型却不是,需要我们自己定义强制进行。
c1=(DerivedC)a2; 进行强制转化,也就是向下转型.

3、记住一个很简单又很复杂的规则,一个类型引用只能引用引用类型自身含有的方法和变量。
你可能说这个规则不对的,因为父类引用指向子类对象的时候,最后执行的是子类的方法的。
其实这并不矛盾,那是因为采用了后期绑定,动态运行的时候又根据型别去调用了子类的方法。而假若子类的这个方法在父类中并没有定义,则会出错。
例如,DerivedC类在继承BaseClass中定义的函数外,还增加了几个函数(例如 myFun())

分析:
当你使用父类引用指向子类的时候,其实jvm已经使用了编译器产生的类型信息调整转换了。
这里你可以这样理解,相当于把不是父类中含有的函数从虚拟函数表中设置为不可见的。注意有可能虚拟函数表中有些函数地址由于在子类中已经被改写了,所以对象虚拟函数表中虚拟函数项目地址已经被设置为子类中完成的方法体的地址了。


4、Java与C++多态性的比较

jvm关于多态性支持解决方法是和c++中几乎一样的,
只是c++中编译器很多是把类型信息和虚拟函数信息都放在一个虚拟函数表中,但是利用某种技术来区别。

Java把类型信息和函数信息分开放。Java中在继承以后,子类会重新设置自己的虚拟函数表,这个虚拟函数表中的项目有由两部分组成。从父类继承的虚拟函数和子类自己的虚拟函数。
虚拟函数调用是经过虚拟函数表间接调用的,所以才得以实现多态的。

Java的所有函数,除了被声明为final的,都是用后期绑定。
C++实现多态性,使用关键字virtual,为了引起晚捆绑,使用虚函数。若一个函数在基类被声明为virtual,则所有子类中都是virtual的。对虚函数的重定义成为越位。

interface Parent 
{ 
String method(); 
} 

class Child1 implements Parent 
{ 
public String method() 
{ 
return "Child1 "; 
} 
} 

class Child2 implements Parent 
{ 
public String method() 
{ 
return "Child2 "; 
} 
} 

public class Test 
{ 
public static void main(String[] args) 
{ 
Parent parent = new Child1(); 
System.out.println(parent.method()); 
parent = new Child2(); 
System.out.println(parent.method()); 
} 
} 

 

输出结果:
Child1
Child2


只有多个子类从一个父类继承或实现一个接口。 在建立这些子类实例时,都用父类或接口做为变量类型,如上例中的parent。也就是说,用户对应的接口都是一个Parent。而由于new后面的子类不同,而产生调用同一个方法method返回不同结果的显现叫多态。就是同一个方法在使用不同子类时有不同的表现(在这里是不同的返回值)。

 

 

 

 

再来看下面这段程序:

class Father {
    public void func1() {
        func2();
    }

    // 这是父类中的func2()方法,因为下面的子类中重写了该方法
    // 所以在父类类型的引用中调用时,这个方法将不再有效
    // 取而代之的是将调用子类中重写的func2()方法
    public void func2() {
        System.out.println("AAA");
    }
}

 

class Child extends Father {
    // func1(int i)是对func1()方法的一个重载
    // 由于在父类中没有定义这个方法,所以它不能被父类类型的引用调用
    // 所以在下面的main方法中child.func1(68)是不对的
    public void func1(int i) {
        System.out.println("BBB");
    }

    // func2()重写了父类Father中的func2()方法
    // 如果父类类型的引用中调用了func2()方法,那么必然是子类中重写的这个方法
    public void func2() {
        System.out.println("CCC");
    }
}

 

public class PolymorphismTest {
    public static void main(String[] args) {
        Father child = new Child();
        child.func1();// 打印结果将会是什么?
    }
}

 

 

    上面的程序是个很典型的多态的例子。子类Child继承了父类Father,并重载了父类的func1()方法,重写了父类的func2()方法。重载后的func1(int i)和func1()不再是同一个方法,由于父类中没有func1(int i),那么,父类类型的引用child就不能调用func1(int i)方法。而子类重写了func2()方法,那么父类类型的引用child在调用该方法时将会调用子类中重写的func2()。

    那么该程序将会打印出什么样的结果呢?

    很显然,应该是“CCC”。

分享到:
评论

相关推荐

    java多态性

    "Java多态性详解" Java多态性是面向对象编程的基本特征之一,它允许子类继承父类,并对父类的方法进行重写或重载,以实现更多的灵活性和可扩展性。在Java中,多态性的体现主要有两种形式:方法的重载和方法的重写。...

    java多态性练习

    Java多态性是面向对象编程中的一个重要特性,它允许我们使用父类引用指向子类对象,从而实现一种灵活的代码设计。在这个“java多态性练习”中,我们将深入探讨多态性的概念、抽象类(abstract class)以及它们在实际...

    实验二:java多态性.rar

    Java多态性是面向对象编程中的一个重要概念,它在Java中起到了关键的作用,使得程序更加灵活,可扩展性更强。本实验将深入探讨Java多态性的核心原理与应用。 首先,我们要理解多态性的基本含义。多态性...

    Java多态性探悉()

    本文将深入探讨Java多态性的概念、实现机制以及相关的编程规则。 一、基本概念 多态性意味着一个接口可以有多种不同的表现形式。在Java中,可以通过子类对象引用赋值给超类对象引用变量来实现这一特性。这意味着,...

    Java-Java面向对象多态性教程

    2. 接口:接口在Java中是多态性的另一种体现。接口是一种完全抽象的类型,它定义了一组方法签名,但不提供具体实现。任何类实现了接口,就必须提供这些方法的实现。通过接口,不同类型的类可以实现相同的接口,从而...

    java多态性详解——父类引用子类对象.pdf

    在 Java 中,多态性是为了解决单继承问题而引入的概念。 第一点,多态性可以通过父类类型的引用指向子类的对象来实现。例如,Animal a = new Cat(); 这里 Animal 是父类,Cat 是子类,a 是 Animal 类型的引用,指向...

    java多态性详解——父类引用子类对象

    本文将深入探讨Java中的多态性,特别是“父类引用子类对象”的概念,以及这一特性如何在实际编码中体现。 ### 多态性概述 多态性主要通过方法的重写(Overriding)、重载(Overloading)和动态绑定(Dynamic Binding)来...

    Java运行时多态性的实现.rar

    本文件“Java运行时多态性的实现.txt”很可能是详细解释这一主题的文档,虽然具体内容无法在此直接提供,但我可以为你总结和扩展相关的Java多态性知识。 1. **类的继承**:在Java中,一个类可以继承另一个类,形成...

    【Java编程教程】详解Java 多态性.pdf

    Java 中的多态性主要分为两种类型:编译时多态和运行时多态。编译时多态主要是通过方法重载(Overloading)实现,即在同一个类中定义多个同名方法,但参数列表不同。而本文将重点讲解运行时多态性,也就是动态绑定或...

    编程语言java多态性.pdf

    Java多态性涉及到的关键词包括:extends(继承)、implements(实现接口)、abstract(抽象类和方法)、virtual(虚函数,C++中的概念)、Override(覆盖)、Overloading(重载)、Encapsulation(封装)等。...

    Java面向对象(进阶)- 面向对象特征之三:多态性

    在Java代码中,多态性的体现就是通过父类引用调用子类重写的方法。例如,定义一个Person类,然后创建一个Man或Woman子类的对象,再用Person类型的引用指向这些子类对象,可以调用子类特有的方法。 ```java public ...

    谈谈对Java多态性的一点理解

    在Java中,多态性主要体现在以下几个方面: 1. 向上转型(Upcasting):这是多态的一种常见形式,即把子类对象赋值给父类引用。例如: ```java Wine a = new JNC(); ``` 在这个例子中,`JNC`对象被赋值给`Wine`类型...

    Java面向对象程序设计多态性.ppt

    在Java中,多态性的概念主要体现在以下几个方面: 1. **单继承结构**:Java不支持多重继承,每个类最多只能有一个父类,这有助于避免复杂的继承关系带来的问题。`Object`类是所有类的最终基类,无论是直接还是间接...

    优质java课件 java程序设计教程(第6版)09.多态性(共41页).ppt

    Java程序设计教程中的第九章——多态性是Java面向对象编程的一个核心概念,它使得代码更具通用性和灵活性。多态性允许一个类型的引用变量指向它的子类型对象,从而调用子类型特有的方法或属性,实现了代码的重用和...

    java 基础练习题

    // 输出 "Dog barks",体现了多态性 } } ``` 这个例子展示了多态性,尽管`animal`变量是`Animal`类型,但实际引用的是`Dog`对象,因此调用的`sound()`方法是`Dog`类中的版本。 3. **练习题** 在学习Java基础...

    基于UML模型的多态性与Java接口代码信息一致性检测的方法.pdf

    4. 多态性扩展:针对UML模型中定义的多态性特性,对生成的时序调用图和代码调用图进行扩展处理,确保多态特性得到正确体现。 5. 检测与修改:通过模型信息对代码信息进行检测,如果发现不一致,利用模型信息对代码...

    Java语言程序设计(第二版)\第05章 类的继承性与多态性.ppt

    如果我们有一个通用的`draw()`方法,那么通过父类`Point`的引用调用`draw()`,实际执行的是子类`Line`或`Circle`中的`draw()`方法,这就是多态性的一个体现。 总结,类的继承性和多态性是Java面向对象编程的重要...

    Java程序设计:chapter06 多态性.ppt

    多态性体现在两个主要方面:静态多态(编译时多态)和动态多态(运行时多态)。 1. 静态多态主要通过方法重载(Overloading)实现,即在一个类中定义多个同名但参数列表不同的方法。在编译阶段,Java根据传入的参数...

Global site tag (gtag.js) - Google Analytics