对象初始化流程: 加载字节码(只加载一次)->初始化字段->父类构造方法->自身构造方法。
静态数据的初始化
静态(static)数据的初始化发生在类字节码(class文件)第一次被加载的时候!并且类字节码(class文件)只会被加载一次。
加载类字节码的工作是类加载器来完成的,那么类字节码什么时候第一次被类加载器加载的?以下三个行为会触发类加载器
去加载字节码。
- 创建该类的对象。(其实类构造方法也就是static方法)
- 调用类的static字段或static方法。
- 手动加载类字节码,
Class.forName("xxx.Xxx")
。
加载字节码(class文件)的结果是生成一个 Class 对象,这个Class对象负责创建普通类的对象。
public class Student {
public static String name = "姓名";
static {
System.out.println("静态作用域,只会调用一次");
}
}
public class Demo {
public static void main(String[] args) {
// 1-触发类字节码被加载
Student s1 = new Student();
// 2-触发类字节码被加载
String name = Student.name;
// 3-触发类字节码被加载
try {
Class clazz = Class.forName("lesson08.lesson0803.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
了解了字节码加载原理就理解static
关键字了,所以说static
字段和方法是属于类的而不属于对象的,它在类第一次被加载的时候就已经分配好了内存。 普通的对象是在创建的时候才分配内存的。
字段的初始化
public class Student {
// 姓名 引用类型
String name;
// 年龄 基本类型
int age;
// 身高 基本类型
float height;
// 分数 包装类型
Integer score;
}
public class Demo {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1.name);// 结果: null
System.out.println(s1.age);// 结果:0
System.out.println(s1.height); // 结果:0.0
System.out.println(s1.score); // 结果:null
}
}
- 类的成员变量如果是
基本类型
,初始化的时候会被赋予默认值
;如果是引用类型
初始化的时候不会被赋值,也就是为null。
利用构造方法(构造器)进行对象初始化
通过new
创建对象一定会调用类的构造方法。如果该类有父类,会先调用父类的构造方法再调用自身的构造方法。
类的构造方法名称跟类名一样,首字母大写。
默认构造方法
每个类都有个默认的构造方法。即使这个类是空的,它也会有个默认的构造方法(只是你看不到)。如下:
public class Demo {
}
看代码
// 父类 人
public class People {
// 默认构造方法(构造器)
public People() {
System.out.println("People()");
}
}
// 子类 学生
public class Student extends People {
// 姓名
public String name;
// 默认构造方法(构造器)
public Student() {
System.out.println("Student()");
}
// 有参构造方法(构造器)
public Student(String name) {
this.name = name;
System.out.println("Student(" + name + ")");
}
}
public class Demo {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student("张三");
/**
* 运行结果:
*
* People()
* Student()
*
* People()
* Student(张三)
*/
}
}
- 创建
s1
、s2
对象都会先调用父类的构造方法People()
,然后调用本身的构造方法Student()
。 - 子类也可以通过
super(参数)
来调用父类特定的构造方法。
结语
关注微信公众号:小虎哥的技术博客,每天一篇文章,让你我都成为更好的自己。
网友评论