构造方法详解.docx
《构造方法详解.docx》由会员分享,可在线阅读,更多相关《构造方法详解.docx(12页珍藏版)》请在冰豆网上搜索。
构造方法详解
5.2.1构造方法的格式
一个新对象的初始化的最终步骤是去调用对象的构造方法。
构造方法必须满足以下条件:
l.方法名必须与类名称完全相匹配;
2.不要声明返回类型;
3.不能被static、final、synchronized、abstract、native修饰。
下列代码中的构造方法都是合法的。
publicclassXyz{
publicXyz(){//No-argconstructor
//setuptheobject.
}
publicXyz(intx){//int-argconstructor
//setuptheobjectusingtheparameterx.
}
}
5.2.2重载构造方法
如果有一个类带有几个构造方法,那么也许会想复制其中一个构造方法的某些操作到另一个构造方法中。
可以通过使用关键字this作为一个方法调用来达到这个目的。
不能通过方法名直接调用构造方法。
publicclassEmployee{
privateStringname;
privateintsalary;
publicEmployee(Stringn,ints){
name=n;
salary=s;
}
publicEmployee(Stringn){
this(n,0);
}
publicEmployee(){
this("Unknown");
}
}
在第二个构造方法中,有一个字符串参数,调用this(n,0)将控制权传递到构造方法的另一个版本,即采用了一个String参数和一个int参数的构造方法。
在第三个构造方法中,它没有参数,调用this("Unknownn")将控制权传递到构造方法的另一个版本,即采用了一个String参数的构造方法。
对于this的任何调用,如果出现在任何构造方法中,必须作为第一个语句。
5.2.3缺省构造方法
缺省构造方法是没有参数的构造方法,你可以显式定义类的缺省构造方法。
为了保证每个类至少有一个构造方法,如果定义的类中一个构造方法也没有写,Java将自动提供一个缺省构造方法。
该构造方法没有参数,用public修饰,而且方法体为空。
格式如下:
publicClassName(){}
只要类中显式定义了一个或多个构造方法,而且所有显式定义的构造方法都带参数,那么将失去缺省构造方法。
举例如下:
publicclassSample1{}
publicclassSample2
{
publicSample2(inta){System.out.println("MyConstructor");}
}
publicclassSample3
{
publicSample3(){System.out.println("MyDefaultConstructor");}
}
可以调用Sample1的缺省构造方法来创建Sample1对象。
Sample1s=newSample1();
Sample2类的缺省构造方法失效,因此以下的创建Sample2对象的方法编译会出错。
Sample2s=newSample2();
正确的创建方法是:
Sample2s=newSample2(0);
Sample3类定义了自己的缺省构造方法,因此以下语句是合法的。
Sample3s=newSample3();
5.2.4子类调用父类的构造方法
父类的构造方法不能被子类继承。
子类不能直接通过方法名调用父类的一个构造方法,而是要通过super关键字调用父类的一个构造方法,super语句必须位于子类构造方法的第一行。
例如:
/**
*Son.java
*/
classGrandPa
{
protectedGrandPa()
{
System.out.println("defaultGrandPa");
}
publicGrandPa(Stringname)
{
System.out.println(name);
}
}
classFatherextendsGrandPa
{
protectedFather()
{
System.out.println("defaultFather");
}
publicFather(StringgrandPaName,StringfatherName)
{
super(grandPaName);
System.out.println(fatherName);
}
}
publicclassSonextendsFather
{
publicSon()
{
System.out.println("defaultSon");
}
publicSon(StringgrandPaName,StringfatherName,StringsonName)
{
super(grandPaName,fatherName);
System.out.println(sonName);
}
publicstaticvoidmain(Stringargs[])
{
Sons1=newSon();
Sons2=newSon("MyGrandPa","MyFather","MySon");
}
}
执行语句:
Sons2=newSon("MyGrandPa","MyFather","MySon");
将会输出如下结果:
MyGrandPa
MyFather
MySon
当子类的某个构造方法没有调用父类的一个构造方法,通过这个构造方法创建子类对象时,会自动先调用父类的缺省构造方法。
对于多级继承,执行缺省构造方法的顺序是从最上层的类开始。
对于以上的代码执行语句Sons1=newSon();
将会输出如下结果:
defaultGrandPa
defaultFather
defaultSon
当子类的某个构造方法没有调用父类的一个构造方法,而父类又没有提供缺省构造方法时,将会出现编译错误。
例如:
修改一下Son.java文件。
去掉GrandPa类中显式定义的缺省构造方法:
protectedGrandPa()
{
System.out.println("defaultGrandPa");
}
这样,GrandPa类中就失去了缺省构造方法,这时,在编译Father类的缺省构造方法时,因为找不到GrandPa类的缺省构造方法而出错。
子类的某个构造方法没有通过super语句调用父类的构造方法,而是通过this语句调用了另一个构造方法,而在另一个构造方法中通过super语句调用了父类的构造方法,这种情况下,父类的缺省构造方法不会被调用。
例如:
classA
{
A(inti){}
}
classBextendsA
{
B(){this(0);}
B(inti){super(i);}
}
对于newB()语句将依次执行如下方法:
1:
A(int)2:
B(int)3:
B()
5.2.5构造方法的作用域
构造方法只能被所在类的其他构造方法或子类的构造方法调用,或在用new语句创建类的实例时被调用。
引用类型的变量不能访问对象的构造方法。
对于以下代码,请读者自己分析某些语句编译出错的原因。
classBase
{
publicBase(inti,intj){}
publicBase(inti){
this(i,0);//CORRECT
Base(i,0);//ERROR
}
}
classSubextendsBase
{
publicSub(inti,intj)
{
super(i,0);//CORRECT
}
voidmethod1(inti,intj)
{
this(i,j);//ERROR
Sub(i,j);//ERROR
}
voidmethod2(inti,intj)
{
super(i,j);//ERROR
}
voidmethod3(inti,intj)
{
Bases=newBase(0,0);//CORRECT
s.Base(0,0);//ERROR
}
}
5.2.6构造方法不能被继承
构造方法可以被子类的构造方法调用,但不能被子类继承。
例如:
classA
{
A(inti){};
A(){}
}
classBextendsA{}
classCextendsB
{
C(){
super.super(0);//COMPILEERROR
A(0);//COMPILEERROR
}
}
由于类B并没有继承类A的构造方法A(inti),所以在构造方法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.Whichlinecontainsaconstructorinthisclassdefinition?
publicclassCounter{//(a)
intcurrent,step;
publicCounter(intstartValue,intstepValue){//(b)
set(startValue);
setStepValue(stepValue);
}
publicintget(){returncurrent;}//(c)
publicvoidset(intvalue){current=value;}//(d)
publicvoidsetStepValue(intstepValue){step=stepValue;}//(e)
}
a)Codemarkedwith(a)isaconstructor
b)Codemarkedwith(b)isaconstructor
c)Codemarkedwith(c)isaconstructor
d)Codemarkedwith(d)isaconstructor
e)Codemarkedwith(e)isaConstructor
答案:
b
解析:
类的构造方法必须遵循以下规则:
方法名和类同名,无返回值。
一个方法同时满足这两个条件,Java编译器就会将其当作类的构造方法。
一个方法如果只满足其中的一个条件,将会编译出错,被认为是不合法的方法声明。
2.Whichofthefollowingcanbeappliedtoconstructors:
a)final
b)static
c)synchronized
d)native
e)Noneofthese.
答案:
e
解析:
构造方法不能被子类继承,所以用final修饰没有意义。
构造方法用于创建一个新的对象,不能作为类的静态方法,所以用static修饰没有意义。
此外,Java语言不支持native或synchronized的构造方法。
3.Whatwillhappenwhenyouattempttocompileandrunthefollowingcode.
publicclassHope{
publicstaticvoidmain(Stringargv[]){
Hopeh=newHope();
}
protectedHope(){
for(inti=0;i<10;i++){
System.out.println(i);
}
}
}
a)Compilationerror:
Constructorscannotbedeclaredprotected
b)Runtimeerror:
Constructorscannotbedeclaredprotected
c)Compilationandrunningwithoutput0to10
d)Compilationandrunningwithoutput0to9
答案:
d
解析:
构造方法可以被public、protected、private修饰。
4.WhatwillhappenifyoutrytocompileandexecuteB´smain()method?
classA{
inti;
A(inti){
this.i=i*2;
}
}
classBextendsA{
publicstaticvoidmain(String[]args){
Bb=newB
(2);
}
B(inti){
System.out.println(i);
}
}
Selecttheonerightanswer.
a)Theinstancevariableiissetto4
b)Theinstancevariableiissetto2
c)Theinstancevariableiissetto0
d)Thiscodewillnotcompile
答案:
d
解析:
由于类B的构造方法B(inti)中没有调用父类的构造方法,而父类中又没有缺省构造方法,导致编译错误。
5.Whathappenswhenyoutrytocompileandrunthefollowingprogram?
classMystery{
Strings;
publicstaticvoidmain(String[]args){
Mysterym=newMystery();
m.go();
}
voidMystery(){
s="constructor";
}
voidgo(){
System.out.println(s);
}
}
Selecttheonerightanswer.
a)thiscodewillnotcompile
b)thiscodecompilesbutthrowsanexceptionatruntime
c)thiscoderunsbutnothingappearsinthestandardoutput
d)thiscoderunsand"constructor"inthestandardoutput
e)thiscoderunsandwrites"null"inthestandardoutput
答案:
e
解析:
这道题中故意设置了一个陷阱,定义了一个貌似构造方法的Mystery()方法。
由于它被声明了返回类型,所以其实不是构造方法。
newMystery()语句其实调用的是类Mystery的缺省构造方法。
6.YesorNo?
Statement1)Ifyoucreateanon-defaultderivedconstructoranddon´tcallthebaseclassconstructor,thecompilerwillcallthedefaultbaseclassconstructorautomatically.(Assumethatthedefaultconstructorisdefinedforthebaseclass).
Statement2)Whataboutifitisnotdefined?
Statement3)Whataboutthecaseofadefaultderivedconstructor,doesthecompiler
callthedefaultbaseclassconstructor
a)Yes,No,Yes
b)Yes,No,No
答案:
a
解析:
子类的构造方法中如果没有调用父类的构造方法,程序运行时会自动先调用父类的缺省构造方法(包括自动提供的缺省构造方法或显式定义的缺省构造方法)。
如果父类没有缺省构造方法,将会编译出错。
7.GiventhefollowingcodehowcouldyouinvoketheBaseconstructorthatwillprintoutthestring"baseconstructor";
classBase{
Base(inti){
System.out.println("baseconstructor");
}
Base(){
}
}
publicclassSupextendsBase{
publicstaticvoidmain(Stringargv[]){
Sups=newSup();
//One
}
Sup()
{
//Two
}
publicvoidderived()
{
//Three
}
}
a)OnthelineAfter//OneputBase(10);
b)OnthelineAfter//Oneputsuper(10);
c)OnthelineAfter//Twoputsuper(10);
d)OnthelineAfter//Threeputsuper(10);
答案:
c
解析:
构造方法只能被所在类的其他构造方法或子类的构造方法调用。
所以在//one、//three处调用构造方法都是非法的。
8.TrueorFalse.
TheClassclasshasnopublicconstructor.
a)True
b)False
答案:
a
解析:
Class类没有公共构造方法,所以Class类的对象不能在程序中通过构造方法创建。
当Java虚拟机装载某个类(假如类名是ClassSample)的时候,会自动调用JVM的类装载器的defineClass()方法,这个方法会创建和某个类ClassSample相关的Class类的对象。
Object类有个方法getClass(),它返回一个Class类的对象。
所以,所有的Java对象都可以通过方法getClass()获得它的Class类的对象。
例如:
ClassSamples=newClassSample();
System.out.println(s.getClass().getName());
将会打印ClassSample。
9.Whichstatementsconcerningthefollowingcodearetrue?
classA{
publicA(){}
publicA(inti){this();}
}
classBextendsA{
publicbooleanB(Stringmsg){returnfalse;}
}
classCextendsB{
privateC(){super();}
publicC(Stringmsg){this();}
publicC(inti){}
}
a)Thecodewillfailtocompile.
b)TheconstructorinAthattakesanintasanargumentwillneverbecalledasaresultofconstructinganobjectofclassBorC.
c)ClassChasthreeconstructors.
d)ObjectsofclassBcannotbeconstructed.
e)AtmostoneoftheconstructorsofeachclassiscalledasaresultofconstructinganobjectofclassC.
答案:
b,c
解析:
在类B中定义的方法B()有返回值,所以它不是构造方法。
类B只有一个缺省构造方法,所以创建类B或类C的对象时,会先调用类B的缺省构造方法,而类B的缺省构造方法会先调用类C的缺省构造方法,类A的构造方法A(inti)永远不会被调用。
选项e是不正确的,newC("hello")语句将调用类C的两个构造方法C()和C(Stringmsg)。
10.Whichofthefollowingcodefragmentsarelegal?
a)classMusicWork{
MusicWork(Strings){
System.out.println("Thenameofthisworkis"+s);
}
}
classClassicalWorkextendsMusicWork{
ClassicalWork(Strings,Stringcomposer){
System.out.println("Thecomposeris"+composer);
}
}
b)classMusicWork{
MusicWork(Strings){
System.out.println("Thenameofthisworkis"+s);
}
}
classClassicalWorkextendsMusicWork{
ClassicalWork(Strings,Stringcomposer){
super(s);
System.out.println("Thecomposeris"+com