`

关于Java构造器

    博客分类:
  • Java
 
阅读更多

关于Java构造器

作者:langm

版权声明:任何获得Matrix授权的网站,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:langm
原文地址:http://www.matrix.org.cn/resource/article/44/44041.html
关键词: Java 构造器

首先要注意的是Java的构造器并不是函数,所以他并不能被继承,这在我们extends的时候写子类的构造器时比较的常见,即使子类构造器参数和父类的完全一­样,我们也要写super就是因为这个原因。
    构造器的修饰符比较的有限,仅仅只有public private
protected这三个,其他的例如任何修饰符都不能对其使用,也就是说构造器不允许被成名成抽象、同步、静态等等访问限制以外的形式。

因为构造器不是函数,所以它是没有返回值的,也不允许有返回值。但是这里要说明一下,构造器中允许存在return语句,但是return什么都不返回,如果你­指定了返回值,虽然编译器不会报出任何错误,但是JVM会认为他是一个与构造器同名的函数罢了,这样就会出现一些莫名其妙的无法找到构造器的错误,这里是要加倍­注意的。

在我们extends一个子类的时候经常会出现一些意想不到的问题,我在这里说一些和构造器有关的。

首先说一下Java在构造实例时的顺序(不讨论装载类的过程)
        构造的粗略过程如下

1、分配对象空间,并将对象中成员初始化为0或者空,java不允许用户操纵一个不定值的对象。
2、执行属性值的显式初始化(这里有一点变化,一会解释,但大体是这样的)
3、执行构造器
4、将变量关联到堆中的对象上

介绍一下准备知识,以备一会来详细说明这个的流程
        this()
super()是你如果想用传入当前构造器中的参数或者构造器中的数据调用其他构造器或者控制父类构造器时使用的,在一个构造器中你只能使用this()或者s­uper()之中的一个,而且调用的位置只能在构造器的第一行,
在子类中如果你希望调用父类的构造器来初始化父类的部分,那就用合适的参数来调用super(),如果你用没有参数的super()来调用父类的构造器(同时也­没有使用this()来调用其他构造器),父类缺省的构造器会被调用,如果父类没有缺省的构造器,那编译器就会报一个错误,注意此处,我们经常在继承父类的时候­构造器中并不写和父类有关的内容,此时如果父类没有缺省构造器,就会出现编译器添加的缺省构造器给你添麻烦的问题了哦。例如:Class
b extends a{public
b(){}}就没有任何有关父类构造器的信息,这时父类的缺省构造器就会被调用。

        举个SL-275中的例子
1 public class Manager extends Employee {
2                 private String department;
3
4                public Manager(String name, double salary, String
dept)
{
5                         super(name, salary);
6                         department = dept;
7                 }
8                 public Manager(String n, String dept) {
9                         super(name);
10                         department = dept;
11                 }
12                 public Manager(String dept) { //
这里就没有super(),编译器会自动地添加一个空参数的缺省super构造器,此时如果Employee类中没有空参数的缺省构造器,那就会导致一个编译错­误
13                         department = d;
14                 }
15 }

你必须在构造器的第一行放置super或者this构造器,否则编译器会自动地放一个空参数的super构造器的,其他的构造器也可以调用super或者thi­s,调用成一个递归构造链,最后的结果是父类的构造器(可能有多级父类构造器)始终在子类的构造器之前执行,递归的调用父类构造器

在具体构造类实例的过程中,上边过程的第二步和第三步是有一些变化的,这里的顺序是这样的,分配了对象空间及对象成员初始化为默认值之后,构造器就递归的从继承­树由根部向下调用,每个构造器的执行过程是这样的:
1、Bind构造器的参数
2、如果显式的调用了this,那就递归调用this构造器然后跳到步骤5
3、递归调用显式或者隐式的父类构造器,除了Object以外,因为它没有父类
4、执行显式的实例变量初始化(也就是上边的流程中的第二步,调用返回以后执行,这个步骤相当于在父构造器执行后隐含执行的,看样子像一个特殊处理)

5、执行构造器的其它部分

这里的步骤很重要哦!!!!!

从这个步骤中可以很明显的发现这个实例初始化时的递归调用过程,估计看过这个你应该能够理解这个递归构造链是怎么样回事了。

这里还是给出SL-275中的一个例子,让你充分理解一下这个递归的过程。

public class Object {
...
public Object() {}
...

}

public class Employee extends Object {
private String name;
private double salary = 15000.00;
private Date birthDate;
public Employee(String n, Date DoB) {
// implicit super();
name = n;
birthDate = DoB;

}

public Employee(String n) {
this(n, null);

 

}
}

public class Manager extends Employee {
private String department;
public Manager(String n, String d) {
super(n);
department = d;

 

}
}

在创建Manager("Joe Smith","Sales"):时,步骤如下
0 basic initialization
0.1 allocate memory for the complete Manager object
0.2 initialize all instance variables to their default values (0 or
null)
1 call constructor: Manager("Joe Smith", "Sales")
1.1 bind constructor parameters: n="Joe Smith", d="Sales"
1.2 no explicit this() call
1.3 call super(n) for Employee(String)
1.3.1 bind constructor parameters: n="Joe Smith"
1.3.2 call this(n, null) for Employee(String, Date)
1.3.2.1 bind constructor parameters: n="Joe Smith", DoB=null
1.3.2.2 no explicit this() call
1.3.2.3 call super() for Object()
1.3.2.3.1 no binding necessary
1.3.2.3.2 no this() call
1.3.2.3.3 no super() call (Object is the root)
1.3.2.3.4 no explicit variable initialization for Object
1.3.2.3.5 no method body to call
1.3.2.4 initialize explicit Employee variables:
salary=15000.00;注意:在父构造器返回后子类才会初始化实例变量的值。
1.3.2.5 execute body: name="Joe Smith"; date=null;
1.3.3 - 1.3.4 steps skipped
1.3.5 execute body: no body in Employee(String)
1.4 no explicit initializers for Manager
1.5 execute body: department="Sales"

这个流程就说明了一切,这个步骤是要注意的。一会还有些内容是要涉及到这里的。

        写在后边的一些在使用构造器中的注意事项。

一、构造器中一定不要创建自身的实例,否则会造成调用栈溢出错误。这个规则也适用于对象的实例变量,如果对象中有自身的引用,这个引用一定不能在定义中或者构造­器中初始化。

class a
{
        a _a = new a();

        public a()
{
        _a = new a();
        a _b = new a();

 

}
}

以上三种情况都会造成栈溢出,呵呵,这样会造成一个无穷递归的调用栈。

二、如果父类是一个抽象类,那通过调用父类的构造器,也可以将它初始化,并且初始化其中的数据。
三、如果你要在构造器中调用一个方法时,将该方法声明为private。
对于这个规则是需要一些说明的,假使你的父类构造器中要调用一个非静态方法,而这个方法不是private的又被子类所重载,这样在实际创建子类的过程中递归调­用到了父类的构造器时,父类构造器对这个方法的调用就会由于多态而实际上调用了子类的方法,当这个子类方法需要用到子类中实例变量的时候,就会由于变量没有初始­化而出现异常(至于为什么子类中的实例变量没有初始化可以参考上边的实例初始化过程),这是Java不想看到的情况。而当父类构造器中调用的方法是一个priv­ate方法时,多态就不会出现,也就不会出现父类构造器调用子类方法的情况,这样可以保证父类始终调用自己的方法,即使这个方法中调用了父类中的实例变量也不会­出现变量未初始化的情况(变量初始化总是在当前类构造器主体执行之前进行)。

这就是我个人对构造器和实例初始化(不包括类载入部分)的一点归纳,欢迎大家指正和补充。

转自:http://groups.google.com/group/jsfajax/msg/143c114f858f88ee

分享到:
评论

相关推荐

    深入理解java构造器机理

    “深入理解Java构造器机理” 在 Java 编程语言中,构造器是一种特殊的方法,用于初始化对象的创建。它是 Java 类中最重要的一个概念。下面将深入讨论构造器的机理、执行顺序、作用及与其他概念的区别。 一、构造器...

    java 构造器的调用

    在Java编程语言中,构造器(Constructor)是一个特殊的方法,主要负责对象的初始化工作。当创建一个新的类实例时,构造器会被自动调用。构造器的名称必须与类名完全相同,且没有返回类型,包括void。理解并熟练运用...

    JAVA构造器

    JAVA构造器

    Java入门理解构造器

    ### Java入门理解构造器 #### 一、构造器的基本概念 在Java中,构造器(Constructor)是一种特殊的方法,主要用于初始化对象。构造器的名字必须与类名相同,并且没有返回类型,甚至连`void`也不可以有。构造器的...

    Java 构造方法

    - **默认构造器**:如果程序员没有定义任何构造方法,Java编译器会自动提供一个无参的默认构造器。但一旦自定义了构造器,这个默认构造器将不再自动生成。 - **参数化构造器**:当需要在创建对象时传入特定值来初始...

    对象和构造器

    在 Java 程序设计中,对象和构造器是两个基本概念。对象是类的实例,构造器是创建对象的特殊方法。 类和对象 在 Java 中,每个对象都是一个类的实例。类是对对象的抽象,定义了对象的属性和行为。类中定义的变量...

    java中构造器内部调用构造器实例详解

    "java中构造器内部调用构造器实例详解" java中的构造器内部调用构造器实例是指在一个构造器中调用另一个构造器,以减少代码的重复和提高代码的可读性。这种做法可以使用this关键字来实现。 在 Java 中,每个类都...

    Java私有构造器使用方法示例

    "Java私有构造器使用方法示例" Java 私有构造器是 Java 编程语言中的一种特殊的构造器,它使用 private 关键字声明,以控制访问权限。私有构造器的主要作用是阻止对象的生成,防止类被实例化和子类化。通过私有构造...

    理解构造器--构造器和方法的区别

    最后,值得注意的是,Java编译器会在构造器中自动插入对超类构造器的调用,如果没有显式指定,会默认调用无参构造器。这在继承层次结构中确保了初始化的连续性。 总之,理解构造器和方法的区别对于Java程序员至关...

    构造方法JAVA构造方法

    Java构造方法是面向对象编程中的一个关键概念,用于初始化新创建的对象。在Java类中,构造方法是一个特殊的方法,它的名字必须与类名完全相同,没有返回类型,甚至不包括void关键字。当我们创建一个类的新实例时,...

    基于Java构造器和Static关键字的研究.pdf

    基于Java构造器和Static关键字的研究.pdf

    JavaString构造器中originalValue.lengthsize

    Java:String构造器中originalValue.length>size的理解

    Java构造器和方法的区别

     要学习Java,你必须理解构造器。因为构造器可以提供许多特殊的方法,这个对于初学者经常混淆。但是,构造器和方法又有很多重要的区别。  原作者:Robert Nielsen 原站:www.javaworld.com  我们说构造器是一...

    Java 构造器原理及用法解析

    Java 构造器原理及用法解析 Java 构造器是 Java 编程语言中的一个基本概念,它们在创建新对象时执行的操作。构造器是 Java 中创建新对象时执行的操作,当 Java 应用程序创建一个类的实例时,它将检查构造器。如果该...

    java 静态块实例块构造器调用

    Java编程语言中,类的初始化过程涉及到静态块(static block)、实例块(instance block)以及构造器(constructor)。这些块的执行顺序对于理解和编写复杂的Java程序至关重要,特别是在涉及继承关系时。下面我们将...

    构造器和方法的区别

    构造器和方法是Java编程语言中的两个核心概念,它们各自承担着不同的角色和功能,但初学者往往容易混淆。为了更好地理解和区分构造器与方法,本文将深入探讨这两个概念的关键差异,包括它们的功能、语法特性以及如何...

    JPA构造器的使用样例

    总的来说,JPA构造器的使用样例展示了如何通过自定义构造器将多表查询的结果映射到自定义的Java对象上,从而更方便地处理数据库查询结果。这种方法不仅可以减少手动转换数据的工作,还可以使代码更清晰、更易于理解...

    Java构造器使用方法及注意事项

    "Java构造器使用方法及注意事项" Java语言中,构造器是一种特殊的方法,用于初始化对象的状态。下面将详细介绍Java构造器的使用方法及注意事项。 一、构造器的使用方法 构造器是一种特殊的方法,用于初始化对象的...

    Java面向对象(基础)- 类的成员之三:构造器(Constructor)

    【Java面向对象(基础)- 类的成员之三:构造器(Constructor)】 构造器是Java中用于初始化新创建对象的特殊方法。当我们使用`new`关键字创建一个对象时,构造器会被自动调用,用于设置对象的初始状态。构造器的名字...

Global site tag (gtag.js) - Google Analytics