什么时候会发生类的初始化
1、创建类的实例,也就是new一个对象
2、访问某个类或接口的静态变量,或者对该静态变量赋值
3、调用类的静态方法
4、反射(Class.forName(“com.qcby.***”))
5、初始化一个类的子类(会首先初始化子类的父类)
6、JVM启动时标明的启动类,即文件名和类名相同的那个类
测试:
创建类的实例,也就是new一个对象
package com.qcby.algorithm;
public class Test01 {
public static void main(String[] args) {
A a = new A();
}
}
class A{
A(){
System.out.println("执行构造函数");
}
{
System.out.println("执行代码块");
}
static {
System.out.println("执行静态代码块");
}
}
运行结果
完善一下:
package com.qcby.algorithm;
public class Test01 {
static {
System.out.println("main所在的类进行初始化");
}
public static void main(String[] args) {
B b = new B();
}
}
class A{
static int a;
A(){
System.out.println("父类执行构造函数");
}
{
System.out.println("父类执行代码块");
}
static {
System.out.println("父类执行静态代码块");
a=10;
}
}
class B extends A{
static int b;
B(){
System.out.println("子类执行构造函数");
}
{
System.out.println("子类执行代码块");
}
static {
System.out.println("子类执行静态代码块");
b=100;
}
}
结果:
从运行结果我们可以看出当JVM虚拟机启动,先初始化main方法所在的类。当我么在new 一个类的对象,如果其父类没有被初始化,则会先初始化他的父类。加载顺序也一目了然了。先加载父类static代码块,然后是子类static代码块,然后是父类代码块,构造函数。子类代码块,构造函数。
访问某个类或接口的静态变量,或者对该静态变量赋值
package com.qcby.algorithm;
public class Test01 {
static {
System.out.println("main所在的类进行初始化");
}
public static void main(String[] args) {
System.out.println(B.b);
// System.out.println(B.b = 1);
}
}
class A{
static int a;
A(){
System.out.println("父类执行构造函数");
}
{
System.out.println("父类执行代码块");
}
static {
System.out.println("父类执行静态代码块");
a=10;
}
}
class B extends A{
static int b;
B(){
System.out.println("子类执行构造函数");
}
{
System.out.println("子类执行代码块");
}
static {
System.out.println("子类执行静态代码块");
b=100;
}
}
代码运行结果
给静态变量复制的操作我在这里就不演示了哈,小伙伴们自己
调用类的静态方法
package com.qcby.algorithm;
public class Test01 {
static {
System.out.println("main所在的类进行初始化");
}
public static void main(String[] args) {
A.study();
}
}
class A{
static int a;
A(){
System.out.println("父类执行构造函数");
}
{
System.out.println("父类执行代码块");
}
static {
System.out.println("父类执行静态代码块");
a=10;
}
public static void study(){
System.out.println("好好学习!");
}
}
运行结果
反射(Class.forName(“com.qcby.***”))
package com.qcby.algorithm;
public class Test01 {
static {
System.out.println("main所在的类进行初始化");
}
public static void main(String[] args) throws Exception{
Class<?> aClass = Class.forName("com.qcby.algorithm.B");
}
}
class A{
static int a;
A(){
System.out.println("父类执行构造函数");
}
{
System.out.println("父类执行代码块");
}
static {
System.out.println("父类执行静态代码块");
a=10;
}
public static void study(){
System.out.println("好好学习!");
}
}
class B extends A{
static int b;
B(){
System.out.println("子类执行构造函数");
}
{
System.out.println("子类执行代码块");
}
static {
System.out.println("子类执行静态代码块");
b=100;
}
}
一个注意点,要抛出一个异常,不然会报错
java: 未报告的异常错误java.lang.ClassNotFoundException; 必须对其进行捕获或声明以便抛出
很好理解,人家怎么知道你到底有没有这个类,要是没有就会抛出ClassNotFoundException。
当通过子类引用父类的静态变量,不会导致子类初始化
package com.qcby.algorithm;
public class Test01 {
static {
System.out.println("main所在的类进行初始化");
}
public static void main(String[] args) {
B.a=666;
}
}
class A{
static int a;
A(){
System.out.println("父类执行构造函数");
}
{
System.out.println("父类执行代码块");
}
static {
System.out.println("父类执行静态代码块");
a=10;
}
public static void study(){
System.out.println("好好学习!");
}
}
class B extends A{
static int b;
B(){
System.out.println("子类执行构造函数");
}
{
System.out.println("子类执行代码块");
}
static {
System.out.println("子类执行静态代码块");
b=100;
}
}
运行结果
通过数组定义类引用,和引用类的常量(不会会发生类的初始化)
package com.qcby.algorithm;
public class Test01 {
static {
System.out.println("main所在的类进行初始化");
}
public static void main(String[] args) {
//通过数组定义类引用
B[]b=new B[10];
//调用静态常量
System.out.println(B.NUMBER);
}
}
class A{
static int a;
A(){
System.out.println("父类执行构造函数");
}
{
System.out.println("父类执行代码块");
}
static {
System.out.println("父类执行静态代码块");
a=10;
}
public static void study(){
System.out.println("好好学习!");
}
}
class B extends A{
static final int NUMBER=666;
int b=100;
B(){
System.out.println("子类执行构造函数");
}
{
System.out.println("子类执行代码块");
}
static {
System.out.println("子类执行静态代码块");
}
}
运行结果:
有什么问题希望小伙伴们在评论区积极留言~