static关键字和类的加载的初始化顺序

static关键字

static的主要作用有:

  1. 修饰属性
  2. 修饰方法
  3. 代码块
  4. 修饰类

修饰属性

Java静态属性和类相关,和具体的实例无关,换句话说,同一个类的不同实例共用一个静态属性。
例如:

class Demo{
    
    
        public int a;
        public static int count;
    }

    public static void main(String[] args) {
    
    
        Demo demo=new Demo();
        demo.a++;
        Demo.count++;

        System.out.println(demo.a);
        System.out.println(Demo.count);
        System.out.println("+++++++++++++++++");
        Demo demo2=new Demo();
        demo.a++;
        Demo.count++;
        System.out.println(demo.a);
        System.out.println(Demo.count);
    }

结果是:

1
1
+++++++++++++
1
2

因为count被static修饰,所有的类共享,且不属于对象,访问使用的时候,直接用类名.count。
这是因为在被static修饰后,在jvm中被放在了方法区中,而只有一份,所以可以共享。

修饰方法

在任何方法上,使用static关键字,这个方法就被称为静态方法

  1. 静态方法属于类,而不属于对象。
  2. 可以直接调用静态方法,无需创建类的实例。
  3. 静态方法可以访问静态数据成员,并可以更改静态数据成员的值。

例如:

public class Demo2 {
    
    

    public int a;
    public static int count;

    public static void method() {
    
    
        count = 100;
       // a = 10; //不能使用非静态的属性
    }
}
public class Test {
    
    
    public static void main(String[] args) {
    
    

        Demo2.method();
        System.out.println(Demo2.count);
    }
}

结果是:在这里插入图片描述
这上面代码,我们可以看出a不可以在method中被调用。而静态的方法可以通过类名直接调用,不需要创建实例化对象。

注意:
静态方法和实例无关,而和类相关,所以:
1、静态方法不能直接使用非静态数据成员或调用方法(非静态数据成员和方法都是实例相关的)
2、this和super两个关键字不能在静态上下文中使用(this指向当前对象,super是当前实例父类实例的引用)
3、main方法是static的

静态属性的初始化

1、定义时初始化,
2、静态代码块初始化
例如:

public static int = 10;//定义时初始化

static{
    
    
	System.out.println("静态代码块")}

注意

在使用的时候,我们使用的时候,那些会用static,那些不用?
最基本的方法:
如果方法执行的时候,需要用到this,就必须不加static
否则,在方法执行的过程中,不会用到this,可以加static,也可以不加

类的加载

什么是类的加载?
jvm在程序执行的时候,需要用到类中的信息,但jvm只能读取内存的数据,所以需要进一步操作,把类中的信息,从硬盘上.class文件读取出来放在合适的位置。
类一旦被加载过一次,则在整个程序的运行期间,不需要被再次加载。在程序运行期间,用到的类,只会加载1次
jvm在实现类的加载,并不是一开始就把所有用到的类全部加载进来,而是真正使用的时候才加载。

当一个类首次被使用,对该类加载,加载的同时,执行类的初始化过程。

例如:

代码示例


class 执行顺序 {
    
    
    public static int a = initStatic();
    {
    
    
        System.out.println("A");
    }
    public 执行顺序() {
    
    
        this("Hello");
        System.out.println("B");
    }

    public 执行顺序(String s) {
    
    
        System.out.println("C");
    }
    public int b = init();
    public static int initStatic() {
    
    
        System.out.println("D");
        return 0;
    }
    public int init() {
    
    
        System.out.println("E");
        return 0;
    }
    static {
    
    
        System.out.println("F");
    }
}

public class 看看打印是什么 {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("1");
        new 执行顺序();
        System.out.println("2");
        new 执行顺序();
        System.out.println("3");
    }
}

分析

观察上面代码,当类加载后,运行后结果是什么?
首先进入main方法,输出一个1,进入类中,执行静态代码初始化:

public static int a = initStatic();
  static {
    
    
        System.out.println("F");
    }

两个是同一级别,谁在前面谁先执行,所以先a,然后调用 initStatic()方法,输出D,然后输出F。静态初始化完成后,进行实例化初始化,然后new一个新对象,首先执行定义初始化,构造代码初始化,按照书写顺序执行。AE。然后执行构造方法,书写顺序执行,CB
第二次因为静态初始化,只执行一次,所以结果是AECB。

结果:

在这里插入图片描述

总结:

在类的加载中,静态初始化只初始化一次,且在类首次用到时,按照静态属性定义初始化,静态代码块初始化,按照书写顺序执行。
而实例对象初始化(非静态时候),第一类:定义时初始化,构造代码块初始化, 按照书写顺序
第二类:构造方法 ,
无论书写顺序,首先执行第一类,然后第二类。

猜你喜欢

转载自blog.csdn.net/weixin_52142731/article/details/113174522