一、引言

本篇文章主要借static修饰符,进一步的理解static与jvm之间联系。

二、总结

1. 基本概念

静态变量:声明独立于对象的静态变量,无论一个类实例化多少对象,静态变量只有一份拷贝,局部变量不能被声明。
静态方法:声明独立于对象的静态方法,静态方法不能使用类的非静态变量。

2. 作用

方便在没有创建对象的情况下调用方法或变量。

3. 深层原理

为了阐明上面的特性,首先我们需要从jvm内存讲起,
先放一张java内存结构图,我们再通过案例分析static修饰的变量放在哪儿。

Java runtimedate.png

从上图可以看出,静态变量存放在方法区中,被所有线程共享的。
而堆中是存放实例对象的,这里简单的描述下堆、栈、方法区。

堆区:
1)存储的全部是对象,每个对象包含一个对应的class,用于接收操作指令。
2)jvm只有一个堆区(heap),并被所有线程共享,堆中不存放基本类型和对象应用,只存放实例化对象。

栈区:
1)栈分为三个部分:基本类型变量区、执行上下文、操作指令区。
2)每个线程包含一个独自的栈,栈中存放的为基本数据类型的对象与堆中实例对象的引用(地址指向堆中的实例对象)。
3)栈中的数据都是私有的,其他栈不能访问。

方法区:
1)也叫静态区,和堆区一样被所有线程共享,方法区中存放的为class和static变量。
2)所存放的数据在整个程序中都是唯一存在的。

简单描述了栈、堆、方法区后,我们再结合案例从内存角度去分析,static的特性是从何而来的。
public class OnePiece {

    private static String captain;
    private String mate;

    public void showSeaman(){
        System.out.println(captain + "和" + mate);
    }
    
    /**
    * 静态方法不能调用非静态变量
    */
    public static void viewSeanman() {
        System.out.println(captain);
        // System.out.println(mate);
    }

    public static void main(String[] args) {
        OnePiece straw = new OnePiece();
        OnePiece.captain = "路飞";
        straw.mate = "索隆";
        straw.showSeaman();

        OnePiece redhair = new OnePiece();
        // OnePiece.captain = "香克斯";
        // redhair.mate = "本·贝克曼";
        redhair.showSeaman();
    }
}

/**
 * 输出:
 *      路飞和索隆
 *      路飞和null
 */
接下来我们再从内存的角度看看。

static内存.png

从上面可以看到当我们调用方法时,因为实例对象在堆中,所以随着对象的销毁,成员变量也就消失了。
但由于静态变量是存在方法区中的,被所有线程共享,并不会随对象销毁而消失。这就解释了static所具有的特性。

三、参考

https://baijiahao.baidu.com/s?id=1636927461989417537&wfr=spider&for=pc

四、最后

受限于MO_or浅薄的知识体系,并没有很好的阐明static为什么具有这些特性,望同行能在评论区点拨指正。

MO_or
25 声望75 粉丝

小菜鸟的成长地。