(转)
很长时间对与构造方法没有很深的认识,但看过一篇介绍他的文章后感觉恍然大悟,故而把文章整理了一下收藏至此。
类的继承机制使得子类可以使用父类的功能(即代码),并且子类也具有父类的类型。下面介绍类在继承关系上的初始化的顺序问题。
示例1:
class SuperClass { SuperClass() { System.out.println("SuperClass constructor"); } } public class SubClass extends SuperClass { SubClass() { System.out.println("SubClass constructor"); } public static void main(String[] args) { SubClass sub = new SubClass(); } }
输出结果:
SuperClass constructor
SubClass constructor
在子类中只实例化了一个子类对象。从输出结果上看,程序并不是一开始就运行自己的构造方法,而是先运行其父类的默认构造方法。注意:程序自动调用其父类的默认构造方法。
示例2:
class SuperClass { SuperClass(String str) { //这不是构造方法! System.out.println("Super with a string."); } } public class SubClass extends SuperClass { SubClass(String str) { System.out.println("Sub with a string."); } public static void main(String[] args) { SubClass sub = new SubClass("sub"); } }
在JDK下编译此程序不能成功。正如上例中说的:程序在初始化子类时先要寻找其父类的默认构造方法,结果没找到,那么编译自然不能通过。
解决这个问题有两个办法:
1.在父类中增加一个默认构造方法。
2.在子类的构造方法中增加一条语句:super(str); 且必须在第一句。
这两种方法都能使此程序通过编译,但就本程序来说运行结果却不相同。
第1种方法的运行结果是:
Sub with a string.
第2种方法的运行结果是:
Super with a string.
Sub with a string.
第2种解决方法实际上是指定编译器不要寻找父类的默认构造方法,而是去寻找带一个字符串为参数的构造方法。
下面介绍对象的初始化顺序问题。
示例3:
class One { One(String str) { System.out.println(str); } } class Two { One one_1 = new One("one-1"); One one_2 = new One("one-2"); One one_3 = new One("one-3"); Two(String str) { System.out.println(str); } } public class Test { public static void main(String[] args) { System.out.println("Test main() start..."); Two two = new Two("two"); } }
输出结果:
Test main() start...
one-1
one-2
one-3
two
在main()方法中实例化了一个Two类的对象。但程序在初始化Two类的对象时,并非先调用Two类的构造方法,而是先初始化Two类的成员变量。这里Two类有3个成员变量,它们都是One类的对象,所以要先调用3次One类的相应的构造方法。最后在初始化Two类的对象。
示例4:
class One{ One(String str) { System.out.println(str); } } class Two { One one_1 = new One("one-1"); One one_2 = new One("one-2"); static One one_3 = new One("one-3"); Two(String str) { System.out.println(str); } } public class Test { public static void main(String[] args) { System.out.println("Test main() start..."); Two two_1 = new Two("two-1"); System.out.println("------------"); Two two_2 = new Two("two-2"); } }
输出结果:
Test main() start...
one-3
one-1
one-2
two-1
------------
one-1
one-2
two-2
如果一个类中有静态对象,那么它会在非静态对象前初始化,但只初始化一次。非静态对象每次调用时都要初始化。
示例5:
class One { One(String str) { System.out.println(str); } } class Two { One one_1 = new One("one-1"); One one_2 = new One("one-2"); static One one_3 = new One("one-3"); Two(String str) { System.out.println(str); } 3 } public class Test { static Two two_3 = new Two("two-3"); public static void main(String[] args) { System.out.println("Test main() start..."); Two two_1 = new Two("two-1"); System.out.println("------------"); Two two_2 = new Two("two-2"); } }
输出结果:
one-3
one-1
one-2
two-3
Test main() start...
one-1
one-2
two-1
------------
one-1
one-2
two-2
程序中主类的静态变量会在main()方法执行前初始化。结果中只输出了一次one-3,这也说明:如果一个类中有静态对象,那么它会在非静态对象前初始化,但只初始化一次。非静态对象每次调用时都要初始化。
示例6:
class One { One(String str) { System.out.println(str); } } class Two { static int i = 0; One one_1 = new One("one-1"); static One one_2 = new One("one-2"); static One one_3 = new One("one-3"); Two(String str) { System.out.println(str); } } public class Test { public static void main(String[] args) { System.out.println("Test main() start..."); System.out.println("Two.i = " Two.i); } }
输出结果:
Test main() start...
one-2
one-3
Two.i = 0
不仅第1次创建对象时,类中所有的静态变量要初始化,第1次访问类中的静态变量(没有创建对象)时,该类中所有的静态变量也要按照它们在类中排列的顺序初始化。
综上所述:
在创建对象时,对象所在类的所有数据成员会首先进行初始化,如果其中的成员变量有对象,那么它们也会按照顺序执行初始化工作。在所有类成员初始化完成后,才调用对象所在类的构造方法创建对象。构造方法作用就是初始化。
静态对象(变量)在非静态对象前初始化。静态对象(变量)只初始化一次,再次调用就不初始化了,但非静态对象在每次调用时都要初始化。
程序中的主类的静态变量会在main()方法执行前进行初始化工作。
不仅第1次创建对象时,类中所有的静态变量要初始化,第1次访问类中的静态变量(没有创建对象)时,该类中所有的静态变量也要按照它们在类中排列的顺序初始化。
初始化的顺序包括构造方法调用的顺序如下:
1.主类的静态成员首先初始化。
2.主类的超类的构造方法按照从最高到最低的顺序被调用。
3.主类的非静态对象(变量)初始化。
4.调用主类的构造方法。
在一个构造方法中只能调用一次其它的构造方法,并且调用构造方法的语句必须是第一条语句。
相关推荐
8.java构造函数.zip8.java构造函数.zip8.java构造函数.zip8.java构造函数.zip8.java构造函数.zip8.java构造函数.zip8.java构造函数.zip8.java构造函数.zip8.java构造函数.zip8.java构造函数.zip8.java构造函数.zip8....
以下是关于Java构造函数继承问题的关键知识点: 1. **继承默认构造函数**: - 子类只能继承父类的无参数(默认)构造函数。如果父类没有无参数的构造函数,那么子类无法直接继承任何构造函数。 - 缺省构造函数是...
Java构造函数是编程中至关重要的概念,特别是在面向对象编程中。它们主要用于初始化新创建的对象的状态。构造函数在类中定义,其名字与类名完全相同,并且没有返回类型,连void也不包含。当通过`new`关键字创建一个...
java构造函数雪花算法生成uuid,开始时间截、机器id所占的位数、数据标识id所占的位数、支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) 、支持的最大数据标识id,...
Java构造函数的相互调用代码示例 Java构造函数的相互调用代码示例是Java编程中的一个重要知识点。通过使用this关键字,可以在一个构造函数中调用另一个构造函数,以减少代码量。下面是相关的知识点: 1. 构造函数...
Java构造函数与普通函数用法详解 Java构造函数和普通函数是Java语言的两个基本组成部分,它们在Java编程中扮演着非常重要的角色。下面我们将详细讲解Java构造函数和普通函数的用法和相关知识点。 一、函数的作用和...
Java构造函数是面向对象编程中的一个关键概念,用于在创建对象时初始化对象的状态。当我们创建一个类的实例时,构造函数会被自动调用,它允许我们设置对象的初始属性值,确保对象在创建后处于一个合理的状态。在这个...
“深入理解Java构造器机理” 在 Java 编程语言中,构造器是一种特殊的方法,用于初始化对象的创建。它是 Java 类中最重要的一个概念。下面将深入讨论构造器的机理、执行顺序、作用及与其他概念的区别。 一、构造器...
### Java中的私有构造函数:理解其特殊用途与设计模式应用 #### 一、引言 在Java编程语言中,构造函数(Constructor)是用于初始化新创建的对象的关键组成部分。默认情况下,构造函数的访问级别设置为`public`,...
在这个场景中,我们关注的是Java继承时构造函数的调用规则。 首先,每个Java类都有一个或多个构造函数,它们的主要作用是在创建对象时初始化对象的状态。如果一个类没有显式定义任何构造函数,Java编译器会自动生成...
在探讨继承中子类与父类构造函数及静态块的执行顺序时,我们首先需要理解构造函数和静态块的基本概念及其在Java中的作用。构造函数主要用于初始化对象的状态,而静态块则是在类加载到内存中时执行的一段代码,通常...
这是因为Java编译器不允许子类构造函数默认调用不存在的父类构造函数。 例如,在以下代码中,因为`Base`类中没有定义任何构造函数(默认构造函数被注释掉),所以`Derived`类中的构造函数尝试调用不存在的`Base`...
Java 泛型构造函数是Java编程中用于增强类型安全性的工具,它们允许我们在类的构造函数中使用类型参数。在创建对象时,泛型构造函数能够确保传入的数据类型符合预定义的约束,从而减少类型转换错误并提高代码的...
在Java编程语言中,构造函数是一种特殊的方法,它在创建对象时被自动调用,用于初始化新创建的对象。本视频“18_构造函数”深入探讨了Java中的构造函数概念,是JavaSE学习的重要组成部分。 首先,我们来理解构造...
### 构造函数继承在Java中的应用 构造函数继承是面向对象编程中一个重要的概念,尤其是在Java这样的语言中。本文将深入探讨构造函数继承的概念、原理及其在Java中的实现方式。 #### 构造函数的基本概念 在Java中...
枚举类型与构造函数 枚举类型是一种特殊的数据类型,它可以在程序中定义一组固定的常量,...枚举类型和构造函数是Java中两种重要的概念,枚举类型可以定义一组固定的常量,而构造函数可以用于初始化对象的实例变量。
### Java:构造函数与对象 #### 第一章:构造函数揭秘——创造者的第一次触碰 在Java编程语言中,构造函数扮演着极其重要的角色。它是一种特殊的成员方法,主要用于对象的初始化过程。构造函数没有返回类型,其...
Java继承时构造函数的调用机制是:子类的构造函数需要调用父类的构造函数,父类的无参数构造函数是默认的,如果父类没有提供无参数构造函数,而提供了其他类型的构造函数,那么编译器将报错。因此,我们最好给父类...
JAVA 构造函数定义过程解析 JAVA 构造函数是类的一种特殊方法,它用于初始化类的对象。构造函数的名称必须与类名相同,且不能返回任何值,包括 void。构造函数的主要作用是初始化类的成员变量,并对对象进行初始化...