<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />11.2.4 构造方法的作用域<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

构造方法只能通过以下方式被调用:

当前类的其他构造方法通过 this 语句调用它。

  当前类的子类的构造方法通过 super 语句调用它。

  在程序中通过 new 语句调用它。

对于例程 11-4 Sub.java )的代码,请读者自己分析某些语句编译出错的原因。

例程 11-4 Sub.java

class Base{

public Base(int i,int j){}

public Base(int i){

this(i,0); // 合法

Base(i,0); // 编译出错

}

}

class Sub extends Base{

public Sub(int i,int j){

super(i,0); // 合法

}

void method1(int i,int j){

this(i,j); // 编译出错

Sub(i,j); // 编译出错

}

void method2(int i,int j){

super(i,j); // 编译出错

}

void method3(int i,int j){

Base s=new Base(0,0); // 合法

s.Base(0,0); // 编译出错

}

}

11.2.5 构造方法的访问级别

构造方法可以处于 public protected private 和默认这 4 种访问级别之一。本节着重介绍构造方法处于 private 级别的意义。

当构造方法为 private 级别时,意味着只能在当前类中访问它:在当前类的其他构造方法中可以通过 this 语句调用它,此外还可以在当前类的成员方法中通过 new 语句调用它。

在以下场合之一,可以把类的所有构造方法都声明为 private 类型。

1 )在这个类中仅仅包含了一些供其他程序调用的静态方法,没有任何实例方法。其他程序无须创建该类的实例,就能访问类的静态方法。例如 java.lang.Math 类就符合这种情况,在 Math 类中提供了一系列用于数学运算的公共静态方法,为了禁止外部程序创建 Math 类的实例, Math 类的惟一的构造方法是 private 类型的。

private Math(){}

在第 7 章的 7.2 节( abstract 修饰符)提到过, abstract 类型的类也不允许实例化。也许你会问,把 Math 类定义为如下 abstract 类型,不是也能禁止 Math 类被实例化吗?

public abstract class Math{…}

如果一个类是抽象类,意味着它是专门用于被继承的类,可以拥有子类,而且可以创建具体子类的实例。而 JDK 并不希望用户创建 Math 类的子类,在这种情况下,把类的构造方法定义为 private 类型更合适。

2 )禁止这个类被继承。当一个类的所有构造方法都是 private 类型的时,假如定义了它的子类,那么子类的构造方法无法调用父类的任何构造方法,因此会导致编译错误。在第 7 章的 7.3.1 节( final 类)中提到过,把一个类声明为 final 类型,也能禁止这个类被继承。这两者的区别是:

  如果一个类允许其他程序用 new 语句构造它的实例,但不允许拥有子类,那么就把类声明为 final 类型。

  如果一个类既不允许其他程序用 new 语句构造它的实例,又不允许拥有子类,那么就把类的所有构造方法声明为 private 类型。

由于大多数类都允许其他程序用 new 语句构造它的实例,因此用 final 修饰符来禁止类被继承的做法更常见。

3 )这个类需要把构造自身实例的细节封装起来,不允许其他程序通过 new 语句创建这个类的实例。这个类向其他程序提供了获得自身实例的静态方法,这种方法称为静态工厂方法,本章第 11.3 节(静态工厂方法)对此做了进一步的介绍。