Java笔记丨18 对象构造与初始化

构造方法

对象都有构造方法

如果没有,编译器加一个default构造方法

思考

抽象类有没有构造方法?(有)

 

调用本类或父类的构造方法

this调用本类的其他构造方法

super调用直接父类的构造方法

this或super要放在第一条语句,且只能够有一条

如果没有this及super,则编译器自动加上super(),即调用直接父类不带参数的构造方法

因为必须令所有父类的构造方法都得到调用,否则整个对象的构建就可能不正确。

示例:ConstructCallThisAndSuper.java

扫描二维码关注公众号,回复: 4539762 查看本文章
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构造方法,所有编译器会说构造方法不存在。

解决方法:

  1. 在B的构造方法中,加入super(3);
  2. 在A中加入一个不带参数的构造方法,A(){}
  3. 去掉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的方法

猜你喜欢

转载自blog.csdn.net/qq_42968048/article/details/84579006