构造方法
对象都有构造方法
如果没有,编译器加一个default构造方法
思考
抽象类有没有构造方法?(有)
调用本类或父类的构造方法
this调用本类的其他构造方法
super调用直接父类的构造方法
this或super要放在第一条语句,且只能够有一条
如果没有this及super,则编译器自动加上super(),即调用直接父类不带参数的构造方法
因为必须令所有父类的构造方法都得到调用,否则整个对象的构建就可能不正确。
示例:ConstructCallThisAndSuper.java
class ConstructCallThisAndSuper
{
public static void main(String[] args){
Person p = new Graduate();
}
}
class Person
{
String name;
int age;
Person(){}
Person( String name, int age ){
this.name=name; this.age=age;
System.out.println("In Person(String,int)");
}
}
class Student extends Person
{
String school;
Student(){
this( null, 0, null );
System.out.println("In Student()");
}
Student( String name, int age, String school ){
super( name, age );
this.school = school;
System.out.println("In Student(String,int,String)");
}
}
class Graduate extends Student
{
String teacher="";
Graduate(){
//super();
System.out.println("In Graduate()");
}
}
结果:
In Person(String,int)
In Student(String,int,String)
In Student()
In Graduate()
一个问题
Class A{
A(int a){}
}
Class B extends A{
B(String s){}//编译不能通过
}
编译器会自动调用B(String s){super();}出错
因为这里没写this也没写super,所以它调用super(),而A中又没有不带参数的构造方法。A中已经有一个构造方法,系统不会添加default构造方法,所有编译器会说构造方法不存在。
解决方法:
- 在B的构造方法中,加入super(3);
- 在A中加入一个不带参数的构造方法,A(){}
- 去掉A中全部的构造方法,则编译器会自动加入一个不带参数的构造方法,称为默认的构造方法
创建对象时的初始化
p=new Person(){{age=18;name=”李明”;}}
这样可以针对没有相应构造函数,但又要赋值。双括号可以同时对字段进行赋值
注意双括号
实例初始化和静态初始化
实例初始化
在类中直接写
{语句…}
实例初始化,先于构造方法{}中的语句执行
静态初始化
static{语句…}
静态初始化,在第一次使用这个类时要执行
其执行的具体时机是不确定的,但总是先于实例的初始化
示例:InitialTest.java
class InitialTest
{
public static void main(String[] args)
{
new InitialTest2(6);
}
int n=10; //step2
{
n++;
System.out.println("InitialTest..."+n);
}
static int x;
static
{
x++;
System.out.println("static..." +x);
}
}
class InitialTest2 extends InitialTest{
//普通的构造方法
InitialTest2(int a){
this.a=a;
System.out.println("this.a=" + a );
}
//这以下的部分会先于上面的构造方法执行
//变量的声明
int a;
//实例初始化
{
System.out.println("InitialTest2..."+this.a);
}
//静态初始化,在类加载时就会执行
static
{
x++;
System.out.println("static2..." +x);
}
}
结果:
static...1
static2...2
InitialTest...11
InitialTest2...0
this.a=6
构造方法的执行过程
1.调用本类或父类的构造方法,直至最高一层(Object)
2.按照声明顺序执行字段的初始化赋值
3.执行构造函数中的各语句
简单地说:
先父类构造,在本类成员赋值,最后执行构造方法中的语句
示例:JavaPConstructor.java
class JavaPConstructor
{
int a=2000; //step2
JavaPConstructor(){
this.a=3000; //step3
}
}
step1:调用Object中的方法
示例:ConstructSequence.java
class ConstructSequence {
public static void main(String[] args){
Person p = new Student("李明", 18, "北大");
}
}
class Person{
String name="未命名"; //step 2
int age=-1;
Person( String name, int age ){
super(); //step 1 不加super()系统也会自动添加
//step 3
System.out.println( "开始构造Person(),此时this.name="+this.name+",this.age="+this.age );
this.name=name; this.age=age;
System.out.println( "Person()构造完成,此时this.name="+this.name+",this.age="+this.age );
}
}
class Student extends Person{
String school="未定学校"; //step2
Student( String name, int age, String school ){
super( name, age ); //step 1
//step 3
System.out.println( "开始构造Student(),此时this.name="+this.name+",this.age="+this.age+",this.school="+this.school );
this.school = school;
System.out.println( "Student()构造完成,此时this.name="+this.name+",this.age="+this.age+",this.school="+this.school );
}
}
结果:
开始构造Person(),此时this.name=未命名,this.age=-1
Person()构造完成,此时this.name=李明,this.age=18
开始构造Student(),此时this.name=李明,this.age=18,this.school=未定学校
Student()构造完成,此时this.name=李明,this.age=18,this.school=北大
一个问题
构造方法内部调用别的方法
如果这个方法时虚方法,结果会如何?
从语法上来说这是合法的,但是有时会造成事实上的不合理
示例:ConstructorInvokeVirtual.java
class ConstructorInvokeVirtual
{
public static void main(String[] args){
Person p = new Student("Li Ming", 18, "PKU");
}
}
class Person
{
String name="未命名";
int age=-1;
Person( String name, int age ){
this.name=name; this.age=age;
sayHello();
}
void sayHello(){
System.out.println( "A Person, name: " + name + ", age: "+ age );
}
}
class Student extends Person
{
String school="未定学校";
Student( String name, int age, String school ){
super( name, age );
this.school = school;
}
void sayHello(){
System.out.println( "A Student, name:" + name + ", age: "+ age + ", school: " + school );
}
}
结果:
A Student, name:Li Ming, age: 18, school: null
在本例中,在构造函数中调用了一个动态绑定的方法sayHello(),这时会使用那个方法被覆盖的定义,而这时对象未完全建立好,所以School还没有赋值
因此,可能的话,在构建器中避免调用任何方法,用尽可能简单的方法使对象进入就绪状态
唯一能够安全调用的是具有final的方法