关于构造方法的定义已经在前面进行了简单的阐述,如需查看原文可以点击这里这篇文章主要是讲解一下关于构造方法的具体使用细节和初始化方法。以及构造方法的执行过程。
调用父类或者本类的构造方法:点击this和super查看之前已经讲过详细的用法
1.this调用本类的构造方法
2.super调用直接父类的构造方法
3.this和super要放在第一条语句,且只能有一条
如果没有使用this和super,则编译器会自动的加上super(),即调用直接父类的不带参数的构造方法。因为必须令所有父类构造方法都必须被调用,因为子类必须首先要满足父类,比如student首先必须满足person类,否则整个对象的构建就可能不正确。
举个例子:
package learning1;
public class person {//person是student的父类
int age;
String name;
public person(String n,int m) {
name = n;
age = m;
System.out.println("已调用person构造方法");
}
}
class student extends person//student是primary类的父类
{
String school;//相对于person类,student类新增的属性变量学校
double score;//相对于person类,student类新增的属性变量分数
public student(String n, int m) {
super(n, m);
System.out.println("已调用student构造方法1");
// TODO Auto-generated constructor stub
}
public student(String name ,int age,String school,double score) {
this(name ,age);
this.school=school;
this.score = score;
System.out.println("已调用student构造方法2");
}
}
class primary extends student{
int grade;
public primary(String name ,int age,String school,double score) {
super(name,age,school,score);
System.out.println("已调用primary构造方法1");
}
public primary(String name ,int age,String school,double score,int grade) {
this(name,age,school,score);
this.grade = grade;
System.out.println("已调用primary构造方法2");
}
}
public static void main(String[] args)
{
person p = new primary("张三",17,"JNU",99,3);
}
程序的执行结果为:
已调用person构造方法
已调用student构造方法1
已调用student构造方法2
已调用primary构造方法1
已调用primary构造方法2
从这个例子中首先可以看出,程序的执行顺序是从父类开始的,如果有父类的父类,那么就从最高层开始,执行至当前类。虽然程序只是new一个新的primary对象,那么牵涉到的构造方法非常多。
逆向来看执行时的调用关系:因为这里new的时候给了五个参数,所以首先是primary的构造方法2的五个参数,但是primary构造方法2又this调用了构造方法1,在构造方法1中使用super调用父类student的构造方法2,同样的,利用this调用student的构造方法1,然后super调用父类person的构造方法。
创建对象初始化
使用双花括号进行赋值,例如:
person p = person(){{age = 17;name = "张三";}};
这种写法主要是针对没有相应的构造函数,但是又要给对应字段赋值的情况。注意这里使用的是双花括号。
实例初始化与静态初始化
1.在类中直接写上{语句…},可以实现实例的初始化,而且是先于构造方法{}中的语句被执行。
2.静态初始化,使用 static{语句…},被static修饰的初始化语句只是在第一次使用这个类时才会被执行。而且这样的语句执行时间不是确定的,但是可以确定的是,一定会先于实例的初始化。
例如:
public class person {
int age;
String name;
public person(String n,int m) {
name = n;
age = m;
System.out.println("已调用person构造方法");
}
{
System.out.println("这里是实例初始化语句。。。");
}
static {
System.out.println("这里是静态初始化语句。。。");
}
}
public static void main(String[] args)
{
person p = new person("张三",17);
}
执行结果如下:
这里是静态初始化语句。。。
这里是实例初始化语句。。。
已调用person构造方法
从执行结果也可以清晰的反应出这样的构造方法和初始化之间的执行关系和顺序。虽然这样的使用方式没有任何问题,但是总感觉这样的初始化怪怪的,直接放花括号,还是少用吧,不利于阅读代码。
构造方法的执行过程遵照以下步骤:
1.调用本类或父类的构造方法,直到最高一层,
2.按照声明顺序执行字段的初始化赋值,
3.执行结构函数中的语句。
简单来说就是先父类再构造,再本类成员赋值(实例初始化),最后执行构造方法中的语句。
问题:如果在构造方法中调用普通方法(虚方法),那么执行顺序如何?结果会如何?
答:从语法上来讲是合理的,但是会造成实际上的不合理。因为当你在调用到父类虚方法时,这时会根据你的输入类型自动定义到子类方法体中,那么这时可能导致父类还没有赋值完成,又跳回子类方法,导致执行错误。所以尽量不要在构造方法中调用虚方法。尽量不要使用方法,用于赋值就好。
例如:
public class person1 {
int age;
String name;
public person1(String n,int m) {
say();
name = n;
age = m;
System.out.println("已调用person构造方法");
}
void say()
{
System.out.println("hello! My name is :"+name);
}
}
class student extends person1
{
String school;//相对于person类,student类新增的属性变量学校
double score;//相对于person类,student类新增的属性变量分数
public student(String name ,int age,String school,double score) {
super(name, age);
this.school=school;
this.score = score;
System.out.println("已调用student构造方法1");
// TODO Auto-generated constructor stub
}
}
public static void main(String []args) {
person1 p = new student("张三",17,"JNU",99);
}
hello! My name is :null
已调用person构造方法
已调用student构造方法1
在上面的程序执行过程中,父类的构造方法中使用了say方法,那么在调用时,就会调用回子类的say函数,这样就会到至name的变量名还没赋值,就跳回子类进行输出,就不能输出正确的结果。
如果你对Java有兴趣,可以了解一下前面几期的基础知识!下面附上链接:
Java编程基础认知:Java学习日记1——基础认知
Java面向对象编程认识:Java学习日记2——面向对象编程认知
Java程序的基本结构认识:Java学习日记3——程序类型与构成认知
Java的输入输出方法总结:Java学习日记4——Java输入输出方法总结
Java的数据类型、变量、常量、运算符:Java学习日记5——数据类型、变量、常量、运算符、数组
Java学习日记6——类、字段、方法、this的使用:Java学习日记6——类、字段、方法、this的使用
Java学习日记7——类的继承、super使用规则:Java学习日记7——类的继承、super使用规则
Java学习日记8——修饰符:Java学习日记8——public、static、private、final、abstract、protected
Java学习日记9——接口(长文预警):Java学习日记9——接口(长文预警)
Java学习日记10——Java中的变量及其传递:Java学习日记10——Java中的变量及其传递
Java学习日记11——多态和虚方法调用:Java学习日记11——多态和虚方法调用