关于java构造器的一些总结

来源:互联网 发布:深圳益玩网络 编辑:程序博客网 时间:2024/04/30 17:02

      首先要注意的是Java的构造器并不是函数,所以他并不能被继承,这在我们extends的时候写子类的构造器时比较的常见,即使子类构造器参数和父类的完全一样,我们也要写super就是因为这个原因。

  构造器的修饰符比较的有限,仅仅只有public private protected这三个,其他的例如任何修饰符都不能对其使用,也就是说构造器不允许被成名成抽象、同步、静态等等访问限制以外的形式。

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

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

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

  构造的粗略过程如下:

  1、分配对象空间,并将对象中成员初始化为0或者空,java不允许用户操纵一个不定值的对象。

  2、执行属性值的显式初始化(这里有一点变化,一会解释,但大体是这样的)。

  3、执行构造器

  4、将变量关联到堆中的对象上


  介绍一下准备知识,以备一会来详细说明这个的流程。

  this() super()是你如果想用传入当前构造器中的参数或者构造器中的数据调用其他构造器或者控制父类构造器时使用的,在一个构造器中你只能使用this()或者super()之中的一个,而且调用的位置只能在构造器的第一行,在子类中如果你希望调用父类的构造器来初始化父类的部分,那就用合适的参数来调用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或者this,调用成一个递归构造链,最后的结果是父类的构造器(可能有多级父类构造器)始终在子类的构造器之前执行,递归的调用父类构造器。 

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

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


class a

{

a _a = new a();


public a()

{

_a = new a();

a _b = new a();

}

}

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


  二、如果父类是一个抽象类,那通过调用父类的构造器,也可以将它初始化,并且初始化其中的数据。

  三、如果你要在构造器中调用一个方法时,将该方法声明为private。

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

原创粉丝点击