面向对象-类的加载和对象的创建(执行顺序分析)
1.Children类
/**
* 一、类的加载顺序
* 1加载器启动找到本类的.class文件,通过extends和implement关键字寻找基类,先加载基类和接口
* 2先初始化父类的static成员变量static代码块和接口的static变量
* 3再初始化本类的static成员变量和static代码块
* 二、类加载之后,对象创建后开始加载
* 1加载父类的非静态成员变量(静态成员变量在类初始化的时候已经加载,非静态成员变量要随对象的创建而初始化)
* 2加载父类的构造函数(构造函数在此类的成员变量加载完毕后加载)
* 3加载本类的非静态成员变量
* 4加载本类的构造函数
*
*
* static变量和代码块随类的加载而加载(同为static顺序加载)
* 非static成员变量随对象的创建而加载
* 成员变量先于构造器加载
* 方法被调用才执行
*
*/
public class Children extends Father implements IFather {
private static int childrenStaticField = Print.printInt("子类静态变量childrenStaticField初始化");
private int childrenNonStaticField = Print.printInt("子类非静态变量childrenNonStaticField初始化");
public Children() {
System.out.println("子类构造方法初始化");
}
static {
System.out.println("子类静态代码块执行");
}
static int childrenStaticMethod(){
System.out.println("子类静态方法执行");
return 50;
}
}
2.Father类
package com.example.javabasicdemo.classobject;
public interface IFather {
/**
* 接口主体中的每个字段声明都是隐式的public、static 和 final
* 接口变量是静态的,因为 Java 接口本身不能被实例化;变量的值必须在不存在实例的静态上下文中分配.
* final 修饰符确保分配给接口变量的值是一个真正的常量,不能被程序代码重新分配.
*/
int iFatherInt = Print.printInt("接口静态变量初始化");
// jdk8后接口可以有已实现的默认方法
default void defaultMethod(){
System.out.println("接口默认方法defaultMethod执行");
}
static void interfaceStaticMethod(){
System.out.println("接口静态方法interfaceStaticMethod执行" );
}
}
3.IFather接口
package com.example.javabasicdemo.classobject;
public interface IFather {
// 接口中的变量默认public static final 修饰,接口不能实例化
int iFatherInt = Print.printInt("接口静态变量初始化");
// jdk8后接口可以有已实现的默认方法
default void defaultMethod(){
System.out.println("接口默认方法defaultMethod执行");
}
static void interfaceStaticMethod(){
System.out.println("接口静态方法interfaceStaticMethod执行" );
}
}
4.打印类
package com.example.javabasicdemo.classobject;
/**
* 打印类
*/
public class Print {
public static int printInt(String s){
System.out.println(s);
return 1;
}
// 入口
public static void main(String[] args) {
Children c = new Children();
// 执行后的得到打印结果
}
}
运行结果
亲自动手,印象更深刻
总结
一、类的加载顺序
- 1加载器启动找到本类的.class文件,通过extends和implement关键字寻找基类,先加载基类和接口
- 2先初始化父类的static成员变量static代码块和接口的static变量
- 3再初始化本类的static成员变量和static代码块
二、类加载之后,对象创建后开始加载 - 1加载父类的非静态成员变量(静态成员变量在类初始化的时候已经加载,非静态成员变量要随对象的创建而初始化)
- 2加载父类的构造函数(构造函数在此类的成员变量加载完毕后加载)
- 3加载本类的非静态成员变量
- 4加载本类的构造函数
- static变量和代码块随类的加载而加载(同为static顺序加载)
- 非static成员变量随对象的创建而加载
- 成员变量先于构造器加载
- 方法被调用才执行
思考
- 什么时候可以将方法定义为静态方法?
当一个方法只提供通用的操作流程,而不在内部引用具体对象的数据时,就可以将方法定义为静态方法。 - 为什么静态方法无法调用非静态方法?
因为Java不会在调用静态方法时传递this,静态方法内没有this当然无法调用实例相关的一切