Java中的构造方法

时间:2021-07-24 19:27:34
在做练习的时候发现自己对构造方法这方面理解的有问题,上网寻求帮助时发现以下的内容不错,故上传,以作参考。     以下内容选自<<Java 2 认证指南与试题解析>>一书,详细的电子文档,请浏览:http://javaschool.learn.to

5.2 构造方法

5.2.1 构造方法的格式
5.2.2 重载构造方法
5.2.3 缺省构造方法
5.2.4 子类调用父类的构造方法
5.2.5 构造方法的作用域
5.2.6 构造方法不能被继承
5.2.7 考察要点
5.2.8 试题解析




5.2.1 构造方法的格式


一个新对象的初始化的最终步骤是去调用对象的构造方法。
构造方法必须满足以下条件:
l. 方法名必须与类名称完全相匹配;
2. 不要声明返回类型; 注:不要声明返回类型,即使返回类型是void 也不是构造方法。
3. 不能被static、final、synchronized、abstract、native修饰。
下列代码中的构造方法都是合法的。

public class Xyz {
public Xyz() { // No-arg constructor
// set up the object.
}
public Xyz(int x) { //int-arg constructor
// set up the object using the parameter x.
}
}


5.2.2 重载构造方法


如果有一个类带有几个构造方法,那么也许会想复制其中一个构造方法的某些操作到另一个构造方法中。可以通过使用关键字this作为一个方法调用来达到这个目的。不能通过方法名直接调用构造方法。

public class Employee {
private String name;
private int salary;
public Employee(String n, int s) {
name = n;
salary = s;
}
public Employee(String n) {
this(n, 0);
}

public Employee() {
this( " Unknown " );
}
}

在第二个构造方法中,有一个字符串参数,调用this(n,0)将控制权传递到构造方法的另一个版本,即采用了一个String参数和一个int参数的构造方法。
在第三个构造方法中,它没有参数,调用this("Unknownn")将控制权传递到构造方法的另一个版本,即采用了一个String参数的构造方法。
对于this的任何调用,如果出现在任何构造方法中,必须作为第一个语句。


5.2.3 缺省构造方法


缺省构造方法是没有参数的构造方法,你可以显式定义类的缺省构造方法。
为了保证每个类至少有一个构造方法,如果定义的类中一个构造方法也没有写,Java将自动提供一个缺省构造方法。该构造方法没有参数,用public 修饰,而且方法体为空。格式如下:
public ClassName(){}
只要类中显式定义了一个或多个构造方法,而且所有显式定义的构造方法都带参数,那么将失去缺省构造方法。
举例如下:

public class Sample1{}
public class Sample2
{
public Sample2(int a){System.out.println("My Constructor");}
}

public class Sample3
{
public Sample3(){System.out.println("My Default Constructor");}
}

可以调用Sample1的缺省构造方法来创建Sample1对象。
Sample1 s=new Sample1();
Sample2类的缺省构造方法失效,因此以下的创建Sample2对象的方法编译会出错。
Sample2 s=new Sample2();
正确的创建方法是:
Sample2 s=new Sample2(0);
Sample3类定义了自己的缺省构造方法,因此以下语句是合法的。
Sample3 s=new Sample3();


5.2.4 子类调用父类的构造方法


父类的构造方法不能被子类继承。子类不能直接通过方法名调用父类的一个构造方法,而是要通过super关键字调用父类的一个构造方法,super语句必须位于子类构造方法的第一行。
例如:

/**
* Son.java
*/
class GrandPa
{
protected GrandPa()
{
System.out.println("default GrandPa");
}
public GrandPa(String name)
{
System.out.println(name);
}

}

class Father extends GrandPa
{
protected Father()
{
System.out.println("default Father");
}

public Father(String grandPaName,String fatherName)
{
super(grandPaName);
System.out.println(fatherName);
}
}

public class Son extends Father
{
public Son()
{
System.out.println("default Son");
}

public Son(String grandPaName,String fatherName,String sonName)
{
super(grandPaName,fatherName);
System.out.println(sonName);
}

public static void main(String args[])
{
Son s1=new Son();
Son s2= new Son("My GrandPa", "My Father", "My Son");
}
}

执行语句:
Son s2=new Son("My GrandPa", "My Father", "My Son");
将会输出如下结果:
My GrandPa
My Father
My Son
当子类的某个构造方法没有调用父类的一个构造方法,通过这个构造方法创建子类对象时,会自动先调用父类的缺省构造方法。对于多级继承,执行缺省构造方法的顺序是从最上层的类开始。
对于以上的代码执行语句Son s1=new Son();
将会输出如下结果:
default GrandPa
default Father
default Son
当子类的某个构造方法没有调用父类的一个构造方法,而父类又没有提供缺省构造方法时,将会出现编译错误
例如:修改一下Son.java文件。去掉GrandPa类中显式定义的缺省构造方法:

protected GrandPa()
{
System.out.println("default GrandPa");
}

这样,GrandPa类中就失去了缺省构造方法,这时,在编译Father类的缺省构造方法时,因为找不到GrandPa类的缺省构造方法而出错。
子类的某个构造方法没有通过super语句调用父类的构造方法,而是通过this语句调用了另一个构造方法,而在另一个构造方法中通过super语句调用了父类的构造方法,这种情况下,父类的缺省构造方法不会被调用。
例如:

class A
{
A(int i){}
}
class B extends A
{
B(){this(0);}
B(int i){super(i);}
}

对于new B()语句将依次执行如下方法:
1:A(int) 2:B(int) 3:B()


5.2.5 构造方法的作用域


构造方法只能被所在类的其他构造方法或子类的构造方法调用,或在用new语句创建类的实例时被调用。引用类型的变量不能访问对象的构造方法。
对于以下代码,请读者自己分析某些语句编译出错的原因。

class Base
{
public Base(int i,int j){}
public Base(int i){
this(i,0); //CORRECT
Base(i,0); //ERROR
}

}
class Sub extends Base
{
public Sub(int i,int j)
{
super(i,0); //CORRECT
}

void method1(int i,int j)
{
this(i,j); //ERROR
Sub(i,j); //ERROR
}
void method2(int i,int j)
{
super(i,j); //ERROR
}
void method3(int i,int j)
{
Base s=new Base(0,0); //CORRECT
s.Base(0,0); //ERROR
}

}

5.2.6 构造方法不能被继承


构造方法可以被子类的构造方法调用,但不能被子类继承。
例如:

class A
{
A(int i){};
A(){}
}
class B extends A{}
class C extends B
{
C(){
super.super(0); //COMPILE ERROR
A(0); //COMPILE ERROR
}
}

由于类B并没有继承类A的构造方法A(int i),所以在构造方法C()中调用类A的构造方法是非法的。


5.2.7 考察要点


l 识别合法的构造方法;
2 构造方法可以被重载,一个构造方法可以通过this关键字调用另一个构造方法,this语句必须位于构造方法的第一行;
3 当一个类中没有定义任何构造方法,Java将自动提供一个缺省构造方法;
4 子类通过super关键字调用父类的一个构造方法;
5 当子类的某个构造方法没有通过super关键字调用父类的构造方法,通过这个构造方法创建子类对象时,会自动先调用父类的缺省构造方法
6 构造方法不能被static、final、synchronized、abstract、native修饰,但可以被public、private、protected修饰;
7 构造方法不是类的成员方法;
8 构造方法不能被继承。


5.2.8 试题解析


1.Which line contains a constructor in this class definition?

public class Counter { // (a)
int current, step;
public Counter(int startValue, int stepValue) { // (b)
set(startValue);
setStepValue(stepValue);
}
public int get() { return current; } // (c)
public void set(int value) { current = value; } // (d)
public void setStepValue(int stepValue) { step = stepValue; } // (e)
}

a) Code marked with (a) is a constructor
b) Code marked with (b) is a constructor
c) Code marked with (c) is a constructor
d) Code marked with (d) is a constructor
e) Code marked with (e) is a Constructor
答案:b
解析:类的构造方法必须遵循以下规则:方法名和类同名,无返回值。一个方法同时满足这两个条件,Java编译器就会将其当作类的构造方法。一个方法如果只满足其中的一个条件,将会编译出错,被认为是不合法的方法声明。

2.Which of the following can be applied to constructors:
a) final
b) static
c) synchronized
d) native
e) None of these.
答案:e
解析:构造方法不能被子类继承,所以用final修饰没有意义。构造方法用于创建一个新的对象,不能作为类的静态方法,所以用static修饰没有意义。此外,Java语言不支持native或synchronized的构造方法。

3.What will happen when you attempt to compile and run the following code .

public class Hope{
public static void main(String argv[]){
Hope h = new Hope();
}

protected Hope(){
for(int i =0; i <10; i ++){
System.out.println(i);
}
}
}

a) Compilation error: Constructors cannot be declared protected
b) Run time error: Constructors cannot be declared protected
c) Compilation and running with output 0 to 10
d) Compilation and running with output 0 to 9
答案:d
解析:构造方法可以被public、protected、private修饰。

4.What will happen if you try to compile and execute B´s main() method?

class A {
int i;
A(int i) {
this.i = i * 2;
}
}
class B extends A {
public static void main(String[] args) {
B b = new B(2);
}
B(int i) {
System.out.println(i);
}
}

Select the one right answer.
a) The instance variable i is set to 4
b) The instance variable i is set to 2
c) The instance variable i is set to 0
d) This code will not compile
答案:d
解析:由于类B的构造方法B(int i)中没有调用父类的构造方法,而父类中又没有缺省构造方法,导致编译错误。

5.What happens when you try to compile and run the following program?

class Mystery {
String s;
public static void main(String[] args) {
Mystery m = new Mystery();
m.go();
}
void Mystery() {
s = "constructor";
}
void go() {
System.out.println(s);
}
}

Select the one right answer.
a) this code will not compile
b) this code compiles but throws an exception at runtime
c) this code runs but nothing appears in the standard output
d) this code runs and "constructor" in the standard output
e) this code runs and writes "null" in the standard output
答案:e
解析:这道题中故意设置了一个陷阱,定义了一个貌似构造方法的Mystery()方法。由于它被声明了返回类型,所以其实不是构造方法。new Mystery()语句其实调用的是类Mystery的缺省构造方法。

6.Yes or No?
Statement1) If you create a non-default derived constructor and don´t call the base class constructor ,the compiler will call the default base class constructor automatically. (Assume that the default constructor is defined for the base class).
Statement2) What about if it is not defined?
Statement3) What about the case of a default derived constructor, does the compiler
call the default base class constructor
a) Yes ,No,Yes
b) Yes,No,No
答案:a
解析:子类的构造方法中如果没有调用父类的构造方法,程序运行时会自动先调用父类的缺省构造方法(包括自动提供的缺省构造方法或显式定义的缺省构造方法)。如果父类没有缺省构造方法,将会编译出错。

7.Given the following code how could you invoke the Base constructor that will print out the string "base constructor";

class Base{
Base(int i){
System.out.println("base constructor");
}
Base(){
}
}

public class Sup extends Base{
public static void main(String argv[]){
Sup s= new Sup();
//One
}
Sup()
{
//Two
}

public void derived()
{
//Three
}
}

a) On the line After //One put Base(10);
b) On the line After //One put super(10);
c) On the line After //Two put super(10);
d) On the line After //Three put super(10);
答案:c
解析:构造方法只能被所在类的其他构造方法或子类的构造方法调用。所以在//one、//three处调用构造方法都是非法的。

8.True or False.
The Class class has no public constructor.
a) True
b) False
答案:a
解析:Class类没有公共构造方法,所以Class类的对象不能在程序中通过构造方法创建。当Java虚拟机装载某个类(假如类名是ClassSample)的时候,会自动调用JVM的类装载器的defineClass()方法,这个方法会创建和某个类ClassSample相关的Class类的对象。Object类有个方法getClass(),它返回一个Class类的对象。所以,所有的Java对象都可以通过方法getClass()获得它的Class类的对象。例如:

ClassSample s=new ClassSample();
System.out.println(s.getClass().getName());

将会打印ClassSample。

9.Which statements concerning the following code are true?

class A {
public A() {}
public A(int i) { this(); }
}
class B extends A {
public boolean B(String msg) { return false; }
}
class C extends B {
private C() { super(); }
public C(String msg) { this(); }
public C(int i) {}
}

a) The code will fail to compile.
b) The constructor in A that takes an int as an argument will never be called as a result of constructing an object of class B or C.
c) Class C has three constructors.
d) Objects of class B cannot be constructed.
e) At most one of the constructors of each class is called as a result of constructing an object of class C.
答案:b,c
解析:在类B中定义的方法B()有返回值,所以它不是构造方法。类B只有一个缺省构造方法,所以创建类B或类C的对象时,会先调用类B的缺省构造方法,而类B的缺省构造方法会先调用类C的缺省构造方法,类A的构造方法A(int i)永远不会被调用。选项e是不正确的,new C("hello")语句将调用类C的两个构造方法C()和C(String msg)。

10.Which of the following code fragments are legal?
a) class MusicWork {
MusicWork(String s) {
System.out.println("The name of this work is" + s);
}
}
class ClassicalWork extends MusicWork {
ClassicalWork(String s, String composer) {
System.out.println("The composer is " + composer);
}
}
b) class MusicWork {
MusicWork(String s) {
System.out.println("The name of this work is" + s);
}
}
class ClassicalWork extends MusicWork {
ClassicalWork(String s, String composer) {
super(s);
System.out.println("The composer is " + composer);
}
}
c) class MusicWork {
MusicWork(String s) {
System.out.println("The name of this work is" + s);
}
}
class ClassicalWork extends MusicWork {
ClassicalWork(String s, String composer) {
System.out.println("This is a work of classical music");
System.out.println("The composer is " + composer);
super(s);
}
}
d) class MusicWork {
MusicWork() {
System.out.println("This is a work of music");
}
MusicWork(String name) {
this();
System.out.println("The name of this work is" + name);
}
}
e) class MusicWork {
MusicWork() {
System.out.println("This is a work of music");
}
MusicWork(String name) {
this();
System.out.println("The name of this work is" + name);
}
MusicWork(String composer) {
this();
System.out.println("The composer of this work is" + composer);
}
}
f) class MusicWork {
MusicWork() {
System.out.println("This is a work of music");
}
MusicWork(String name) {
System.out.println("The name of this work is" + name);
this();
}
}

答案:b,d
解析:选项a中必须为父类提供缺省构造方法。选项c中没有把super语句放在构造方法的第一行。选项e中有两个Music(String)构造方法,不合法。选项f中没有把this语句放在构造方法的第一行。

11.Given the following class definition which of the following can be legally placed after the comment line//Here ?

class Base{
public Base(int i){}
}

public class MyOver extends Base{
public static void main(String arg[]){
MyOver m = new MyOver(10);
}
MyOver(int i){
super(i);
}

MyOver(String s, int i){
this(i);
//Here
}
}

a) MyOver m = new MyOver();
b) super();
c) this("Hello",10);
d) Base b = new Base(10);
答案:d
解析:类MyOver没有缺省构造方法,所以选项a不正确。