JavaSE:static关键字详解

引言

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

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

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可以和四大访问修饰符组合使用

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的方法区当中

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

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

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

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

静态变量+静态方法

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

代码+内存图的讲解
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中只存在一份

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
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方法运行

public class OtherPackageClass {

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

运行结果:
在这里插入图片描述
我们可以看到代码块的运行顺序是非常靠前的,只要类实例化(构造方法运行之后),代码块就会运行

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

demo2

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

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

    }

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

    }
}

运行结果

在这里插入图片描述

静态代码块

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

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

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

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

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

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


    public static void main(String[] args) {

    }
}

运行结果:
在这里插入图片描述
我们发现只有静态代码块执行了

demo2

如果我们再创建一个对象

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

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

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方法之后的静态代码块执行!");
    }
}

运行结果

在这里插入图片描述

在这里插入图片描述
如果你觉得我写的不错,可以给我点个赞,这对我真的很重要,谢谢!!!

  • 46
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习JavaSE可以通过以下几个步骤进行: 1. 了解JavaSE的基础知识:JavaSEJava的标准版,主要用于开发桌面应用程序。你可以开始学习JavaSE的基础语法、数据类型、控制流程等内容。可以参考\[3\]中提到的Java是一种跨平台、面向对象的高级程序设计语言,其语法和C++类似。 2. 学习JavaSE的核心概念:JavaSE包含了许多核心概念,如面向对象编程、异常处理、多线程等。你可以通过阅读相关的教程、书籍或参加培训课程来深入学习这些概念。 3. 实践编写JavaSE程序:学习JavaSE最好的方式是通过实践编写程序来加深理解。你可以尝试编写一些简单的JavaSE应用程序,如控制台程序、图形界面程序等。通过实践,你可以更好地理解JavaSE的各种特性和用法。 4. 参考JavaSE的官方文档和教程:JavaSE有详细的官方文档和教程,你可以参考官方文档来了解JavaSE的各种API和用法。此外,还可以参考一些优秀的JavaSE教程和书籍,如《Java核心技术》等。 总结起来,学习JavaSE需要掌握基础知识、核心概念,并通过实践编写程序来加深理解。同时,参考官方文档和教程可以帮助你更好地学习和应用JavaSE。 #### 引用[.reference_title] - *1* *2* *3* [教你如何正确学习JAVASE](https://blog.csdn.net/jsqzy/article/details/120726118)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值