JavaSE:static关键字详解

引言

我们在学习Java的过程中,static属于我们最先遇到的几个关键字之一

你可能会问,我怎么没印象

java 复制代码
public class StaticKeyword {
	// 我们写第一个java程序,运行Hello World的时候,main方法就用了static修饰
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

事实上,作为程序入口的main方法,是一个静态方法

static是我们的老熟人,但是你真的了解她吗?

static关键字简介

static使用

static关键字,是java的关键字之一,表示"静态"

可以用来修饰变量,方法(比如main方法),代码块不能修饰类

static可以和四大访问修饰符组合使用

java 复制代码
public class StaticKeyword {

    private static int a;

    protected static int b;

    static int c;

    public static int d;


    private static void test1() {

    }

    protected static void test2() {

    }


    static void test3() {

    }

    public static void test4() {

    }

    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

static内存存储

只要是static修饰的,都存储在JVM的方法区当中

准确来说,是存储在方法区的类信息之中,所以静态变量/静态方法/静态代码块,本质上归类所有

静态变量存储于静态常量池中;

当静态常量池不满时,静态方法可以存储于其中;否则要存储到方法区的其他区域

静态代码块比较特殊,我们稍后单独处理

静态变量+静态方法

静态变量+静态方法在本类之中 共享,本类的任何对象都可以直接调用

代码+内存图的讲解
java 复制代码
public class StaticKeyword {

    private String c;

    private String f;

    private static int a;

    public static int d;
    

    public static void main(String[] args) {
        StaticKeyword s1 = new StaticKeyword();
        StaticKeyword s2 = new StaticKeyword();
        s1.c = "c1";
        s2.c = "c2";
        s1.a = 1;
        s2.a = 2;

        System.out.println(s1.c + "," + s1.a);
        System.out.println(s2.c + "," + s2.a);

    }

}

输出结果

静态变量a根属于类StaticKeyword,在整个JVM中只有一份,后赋值会覆盖前赋值

但是普通变量c根属于StaticKeyword的对象,堆内存中的对象可以创建很多个,所以c变量赋值互不干扰

静态方法也是如此,在JVM中只存在一份

java 复制代码
public class StaticKeyword {
    
    public static void test1() {
        System.out.println("test1");
    }
        public void test2(){
        System.out.println("test2");
    }

    public static void main(String[] args) {
        StaticKeyword s1 = new StaticKeyword();
        StaticKeyword s2 = new StaticKeyword();

        s1.test1();
        s2.test1();

    }

}

运行结果
s1.test1()执行时,从方法区的静态常量池当中拷贝一份入栈,运行完出栈;

s2.test1()执行时,也从方法区的静态常量池的相同位置拷贝一份入栈,运行完出栈。

test2()在对象实例化的时候从类信息拷贝,但是实际执行时,是从堆内存的不同对象当中拷贝入栈

静态方法不存在相互覆盖的情况,但是需要注意的是别的内容

  1. 静态方法不能调用非静态方法,

    因为有类不一定有对象,类不一定实例化创建了对象,所以存储于对象当中的非静态方法的调用就无从谈起(没有蒸锅怎么煮米)

  2. 非静态方法可以调用静态方法

    因为有对象一定有类,而且静态方法是类共享的

静态变量和静态方法习惯调用形式

既然静态变量和静态方法都是属于类,那么我们实际上可以使用类名+变量名/方法名来访问

事实上,这也是大多数情况下的访问方法,我们都习惯如此

如果不这样做,用对象访问,其实也没什么问题,但是我们通常不会这么做

IDEA也会抛出警告

用类名访问,则不会抛出警告

静态代码块

代码块

代码块中的代码,只能在代码块的范围内执行,代码块中定义的变量是局部变量

代码块根属于对象,存储在堆内存中

代码块只有对象实例化之后才能执行,这一点非常重要

demo1
java 复制代码
public class StaticKeyword {

    public static int a;

    public static void test1() {
        System.out.println("test1");
    }

    public void test2() {
        System.out.println("test2");
    }
		
		// 代码块
    {
        int aaa = 100;
        System.out.println(aaa);
        System.out.println("代码块执行!");
    }

}

在其他类里面的main方法运行

java 复制代码
public class OtherPackageClass {

    public static void main(String[] args) {
        StaticKeyword s1 = new StaticKeyword();
        s1.test2();
    }
}

运行结果:

我们可以看到代码块的运行顺序是非常靠前的,只要类实例化(构造方法运行之后),代码块就会运行

但是若类不实例化,那么就不会执行

demo2

需要注意的是,每次创建一个对象,代码块都会执行一次

java 复制代码
public class OtherPackageClass {
    {
        System.out.println("代码块执行啦!!!");

    }

    public static void main(String[] args) {
        OtherPackageClass o1 = new OtherPackageClass();
        OtherPackageClass o2 = new OtherPackageClass();

    }
}

运行结果

静态代码块

所谓静态代码块,就是被static修饰的代码块

它也具有代码块的一些特征,比如静态代码块中的代码,只能在静态代码块的范围内执行,静态代码块

中定义的变量是局部变量等

区别
  1. 静态代码块根属于类 ,存储在方法区当中;代码块根属于对象,存储在堆中
  2. 只要类加载,静态代码块就会自动执行,而且最优先执行;代码块的执行不光需要类加载,还需要类实例化(创建对象)
demo1
java 复制代码
public class StaticKeyword {

    {
        int aaa = 100;
        System.out.println(aaa);
        System.out.println("代码块执行!");
    }

    static{
        System.out.println("静态代码块执行!");
    }


    public static void main(String[] args) {

    }
}

运行结果:

我们发现只有静态代码块执行了

demo2

如果我们再创建一个对象

java 复制代码
public class StaticKeyword {

    {
        int aaa = 100;
        System.out.println(aaa);
        System.out.println("代码块执行!");
    }

    static{
        System.out.println("静态代码块执行!");
    }


    public static void main(String[] args) {
        StaticKeyword s1 = new StaticKeyword();
    }
}

运行结果:

静态代码块和代码块都执行,并且静态代码块先执行

总结

有对象(创建对象将类实例化)则一定有类(类加载),但是有类(类加载)不一定有对象(创建对象将类实例化)

类加载之后的代码执行顺序

  1. main方法之前的静态代码块
  2. main方法之后的静态代码块
  3. 类实例化之前的main方法代码
  4. main方法之前的代码块(需要类实例化)
  5. main方法之后的代码块(需要类实例化)
  6. 类实例化之后的main方法代码
demo

看懂这个代码,你的静态代码块就过关啦!!!

java 复制代码
public class StaticKeyword {

    private static String name;

    private Integer age;

    {
        System.out.println("4. StaticKeyword类实例化之后,main方法之前的代码块执行!");
    }

    static {
        System.out.println("1. main方法之前的静态代码块执行!");
    }

    public void hhh() {
        System.out.println("哈哈哈哈哈哈");
    }

    public static void main(String[] args) {
        // StaticKeyword类实例化之前
        StaticKeyword.name = "樱岛麻衣天下第一";
        System.out.println("3. StaticKeyword类实例化之前的部分main代码执行:" + StaticKeyword.name);
        System.out.println("=====================================");
        // StaticKeyword类实例化之后
        StaticKeyword s1 = new StaticKeyword();
        s1.age = 18;
        System.out.println("6-1. StaticKeyword类实例化之后的部分main方法代码执行," + "s1对象创建:" + s1.age);
        StaticKeyword s2 = new StaticKeyword();
        s2.age = 30;
        System.out.println("6-2. StaticKeyword类实例化之后的部分main方法代码执行," + "s2对象创建:" + s2.age);
    }

    {
        System.out.println("5. StaticKeyword类实例化之后,main方法之后的代码块执行!");
    }

    static {
        System.out.println("2. main方法之后的静态代码块执行!");
    }
}

运行结果

如果你觉得我写的不错,可以给我点个赞,这对我真的很重要,谢谢!!!

相关推荐
冰淇淋烤布蕾9 分钟前
EasyExcel使用
java·开发语言·excel
拾荒的小海螺15 分钟前
JAVA:探索 EasyExcel 的技术指南
java·开发语言
Jakarta EE32 分钟前
正确使用primefaces的process和update
java·primefaces·jakarta ee
马剑威(威哥爱编程)40 分钟前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
java—大象1 小时前
基于java+springboot+layui的流浪动物交流信息平台设计实现
java·开发语言·spring boot·layui·课程设计
杨哥带你写代码2 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端
camellias_2 小时前
SpringBoot(二十一)SpringBoot自定义CURL请求类
java·spring boot·后端
布川ku子2 小时前
[2024最新] java八股文实用版(附带原理)---Mysql篇
java·mysql·面试
向阳12182 小时前
JVM 进阶:深入理解与高级调优
java·jvm
背水2 小时前
初识Spring
java·后端·spring