`
rootjo
  • 浏览: 17241 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

构造方法内部的多态方法的行为

阅读更多
序:
希望此文可给站在java起点上的J友们一点启示
在此感谢MARS,久城等朋友给我的帮助

引子:昨天在一群里看到如下一段代码,让我郁闷了一下午:
class Super{
  int i = 10;
  public Supper(){
     print();
     i = 20 ;
   }

void print(){
  System.out.println(i);
}
}
class Sub extends Supper{
  int i = 30;
  public Sub(){
    print();
    super.print();
    i = 40;
}

void print(){
  System.out.println(i);
}
}
public class TestExtends{
   public static void main(String [] args){
      new Sub();
}
}
对于这道题,我的答案是:10 30 20
可运行的结果是: 0 30 20
   看到答案让我很是费解,按照方法的调用顺序:在调用子类的构造方法之前先调用父类的构造方法,在执行构造方法的语句之前先初始化成员变量。按照这个顺序得到的应该是我预期的答案。
  在解答此问题之前,让我们先回顾一下多态的几个知识点:
多态:在运行时刻接口匹配的对象能互换的能力,即,多态使得你可以向对待父类的成员那样对待派生类的成员。简单的说:就是用基类的引用指向之类的对象
多态的三个必要条件:
1)要有继承
2)要有重写(覆盖)
3)父类引用指向子类对象
   在Java语言机制中,多态表现为后绑定(或者叫动态绑定、晚期绑定),有两种形式:继承父类并重载父类中具有相同签名的方法(即overriding或者overwriting);实现抽象父类(或接口)中具有相同签名的方法。当你对由父类声明的对象调用该方法时,对应的子类中的方法就会被调用。即运行时会根据对象类型找覆盖之后的方法;
    一般的方法内部,动态绑定的调用是在运行时才决定的,因为对象无法知道它是属于方法所在的那个类,还是属于那个类的子类。
  如果要调用构造方法内部的一个动态绑定方法,就要用到那个方法的被覆盖后的定义。然而这个调用的效果可能相当难以预料,因此被覆盖的方法在对象被完全构造之前就会被调用
  从概念上讲,构造方法的工作实际上是创建对象。在任何构造方法内部,整个对象可能只是部分形成--我们知道基类已经进行初始化。如果构造方法只是在构建对象过程中的一个步骤,并该对象所属于的类是从构造方法所属的类导出的,那么导出部分在当前构造方法被调用的时刻仍旧是没有被初始化的。然而,一个动态绑定的方法调用却会向外深入到继承层次结构内部,它可以调用子类里的方法。如果我们是在构造方法内部这样做,那么就可能会调用某个方法,而这个方法所操纵的成员可能还未进行初始化。
论证:
class Glyph{
void draw(){ print("Glyph.draw()");}
Glyph(){
  print("Glyph() before draw()");
  draw();
  print("Glyph() before draw()");
}

public static void print(String s){
  System.out.println(s);
}
}
class RoundGlyph extends Glyph{
private int radius = 1;
RoundGlyph(int r){
  radius = r;
  print("RoundGlyph.RoundGlyph(), radius = " + radius);
}
void draw(){
  print("RoundGlyph.draw(), radius = " + radius);
}
}
public class PolyConstructors{
public static void main(String[] args){
  new RoundGlyph(5);
}
}
输出结果:
Glyph() before draw()
RoundGlyph.draw(), radius = 0
Glyph() before draw()
RoundGlyph.RoundGlyph(), radius = 5
说明:Glyph.draw()方法设计为将要被覆盖,这种覆盖是在RoundGlyph中发生的。但是Glyph构造方法会调用这个方法,结果导致了对RoundGlyph.,draw()的调用,这看起来似乎是我们的目的。但是如果看输出结果,我们会发现当Glyph的构造方法调用draw()方法时,radius不是默认初始值1,而是0。
揭秘:初始化的实际过程:
1)在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零。
2)调用基类构造方法。此时,被覆盖后的draw()方法(要在调用RoundGlyph构造方法之前调用),由于步骤1的缘故,我们此时会发现radius的值为0.
3)按照声明的顺序调用成员的初始化方法。
4)调用子类的构造方法主体
这样做的优点是什么呢?那就是所有东西都至少初始化为零(或者是某些特殊数据类型中与“零”等价的值)而不是仅仅留作垃圾。其中包括通过组合而嵌入一个类内部的对象引用其值是null。
  到这里,也就明白了开头那道问题的输出,调用Sub的时候先调用其构造方法。由于Sub继承了Super,所以又调用Super的构造方法,而print方法被重写了,调用Sub的print方法,这时候Sub还没有加载,i还没被赋值,所以输出默认值0。

分享到:
评论

相关推荐

    Java中构造器内部的多态方法的行为实例分析

    Java中构造器内部的多态方法的行为实例分析是Java编程语言中一个非常重要的知识点,本文将详细介绍Java中构造器内部的多态方法的行为,结合实例形式分析了java构造器内部多态方法相关原理、功能及操作技巧。...

    第5章(接口与多态).ppt

    构造方法可以是多态的,通过方法覆盖实现。 内部类是 Java 中的一种机制,它允许在一个类中定义另一个类。内部类可以访问外部类的私有成员,反之亦然。内部类可以是静态的,也可以是非静态的。 接口和多态是 Java ...

    java---- 封装,接口,继承,覆盖,构造过程,多态,static、this、super、final用法

    封装是指将对象的状态(属性)和行为(方法)捆绑在一起,并且隐藏对象的内部实现细节,只暴露必要的接口供外部调用的过程。 **特点:** 1. **隐藏内部实现细节:** 对象的内部状态和实现细节被隐藏起来,用户只能...

    Java 语言程序设计:第5章接口多态.ppt

    多态可以与构造方法结合使用,以实现更加灵活的编程。 5.6 内部类 内部类是 Java 语言中的一种嵌套类,它可以访问外部类的成员变量和方法。内部类可以用来实现多态,例如,声明一个内部类 Shape2D,可以利用它来...

    封装、继承、多态.docx

    构造方法是类的特殊方法,它是在创建对象时调用的。构造方法的特点是: 1. 构造方法的名称与类名相同。 2. 构造方法没有返回类型。 3. 构造方法只能在创建对象时调用。 五、 面试题 Java 面向对象的三大特性是:...

    用一个示例来说明C#中的继承、封装和多态

    2. **封装(Encapsulation)**:封装是将数据和操作数据的方法捆绑在一起,隐藏对象的内部细节,只暴露必要的公共接口。这提高了代码的安全性,防止外部代码随意修改对象的状态。 3. **多态(Polymorphism)**:...

    java继承与多态

    通过继承,子类不仅获得了父类的所有属性和方法,还可以扩展或覆盖父类的行为。 **2.2 继承的语法** 在Java中实现继承的基本语法如下: ```java public class SubClass extends SuperClass { // 子类代码 } ``` ...

    Java语言程序设计:JAVA_6-接口与多态、内部类.ppt

    多态是指同一个方法可以具有不同的行为,这取决于所传递的参数类型。多态可以通过方法覆盖或方法重载来实现。 在Java语言程序设计中,内部类是指在一个类的内部定义的类。内部类可以访问外部类的成员变量和方法。...

    Java学习课件第5章接口与多态.ppt

    构造方法不参与多态,因为它们是类的实例化过程的一部分,与具体的类紧密相关。但是,构造方法可以在子类中被重写以满足特定的初始化需求。 **5.6 内部类** 内部类是Java中一种特殊的形式,它在一个类的内部定义。...

    06【类与对象、封装、构造方法】1

    this关键字用于在类的内部引用当前对象,它可以用来区分成员变量和局部变量,也可以在构造方法中引用其他构造方法,或者在方法中调用本类的其他方法。 【面向对象的三大特性】 除了封装之外,面向对象还有另外两个...

    第六章 面向对象(下).ppt

    本章主要探讨了面向对象的一些关键特性,包括`this`与`super`的使用,构造方法的多态与继承,抽象类,接口,以及类的其他相关内容。 1. `this`与`super` `this`关键字在Java中代表当前对象的引用,常用于在方法...

    day07【类与对象、封装、构造方法】.pdf

    类与对象、封装、构造方法 类和对象是面向对象编程的基础概念,它们之间的关系是面向对象编程的核心。类是对一类事物的描述,是抽象的;对象是一类事物的实例,是具体的。类是对象的模板,对象是类的实体。 面向...

    c++ 的封装继承多态例子

    同时,这些类可能会有私有数据成员,以及公有构造函数和访问器方法,体现封装特性。如果文件中还有其他类,可能是为了展示如何通过继承和多态构建复杂的类层次结构。 通过学习和实践这些例子,开发者能够更好地理解...

    06.【类与对象、封装、构造方法】.zip

    Java是一种广泛使用的面向对象的编程语言,其核心概念包括类与对象、封装和构造方法。在Java中,类是创建对象的蓝图,而对象则是程序中的实体,它们代表了现实世界中的具体事物或抽象概念。封装是面向对象编程的一个...

    继承和多态笔记.docx

    - `super`:用来访问父类中的成员,可以调用父类的构造函数或访问父类中的成员变量和方法。 - `this`:指向当前对象的引用,用于访问当前对象的成员。 #### 多态 - **定义**:多态是指同一个操作作用于不同的...

    java 三大特性--封装、继承和多态理解

    例如,私有变量只能在类内部访问,而公共方法提供了一个安全的接口供外部代码与私有数据交互。此外,Java还支持构造器,用于初始化对象的状态,以及getter和setter方法,实现数据的读取和修改。 **继承**是面向对象...

    实验三:Java类与对象

    `Monkey`类中有默认构造方法和带参数的构造方法,后者允许我们在创建对象时立即设置属性值。 接着,我们学习了如何创建和使用对象。在Java中,通过`new`关键字和类的构造方法来创建对象。实验中,我们创建了两个`...

Global site tag (gtag.js) - Google Analytics