【Java核心技术卷】理解static (内存图描述)

演示

下面围绕这段代码进行相关内容的展示
Student类


public class Student {
    private String name;
    private int age;
    static String room;

    public Student(){
    }
    public Student(String name,int age){
        this.age = age;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

测试代码

public class Main {
    public static void main(String args[])
    {
        //首先设置一下教室,这是静态的东西,应该通过类名称进行调用
        Student.room = "101教室";
        Student one = new Student("郭靖",20);
        System.out.println("one的名字: " + one.getName());
        System.out.println("one的年龄: " + one.getAge());
        System.out.println("one的教室: "+ Student.room);
        System.out.println("=============");

        Student two = new Student("黄蓉",18);
        System.out.println("two的名字: " + two.getName());
        System.out.println("two的年龄: " + two.getAge());
        System.out.println("two的名字: " + Student.room);
    }
}

结果:
【Java核心技术卷】理解static (内存图描述)_第1张图片
下面探究static如何实现共享的.

图解

【Java核心技术卷】理解static (内存图描述)_第2张图片

1.首先关注方法区
JVM加载核心类(如Object)等东西之后,要扫描main方法,发现Student类之后, 进行装载,在方法区设置相应虚拟的表.表中有虚方法表,实方法表,实例字段与静态字段(可能有接口方法表),
注意 静态字段存储的东西放在一个独立的空间(被称为静态区),虚拟的表中的静态字段中的room指向这块空间
这个阶段执行:

  1. 加载静态字段
  2. 加载静态方法
  3. 加载静态代码块并执行

2.关注堆区
JVM设置这张虚拟的表之后, 通过new关键字为Student类,创建了one和two两个对象,都是进行
4. 实例变量初始化
5. 加载实例构造方法初并执行
6. 加载实例方法
(个人笔记,有的方法可能没有,但是为了加深认识,把整个顺序都写上了,)

3.关注栈区
堆区的实例对象初始化完成后,将地址赋值给栈区的one,two引用变量

从代码和内存图中可以看出根据类名称访问静态成员变量的时候,全程和对象就设关系,只和类有关系

当然在堆区,实例对象加载了静态字段room,也可以通过one.room和two.room来访问,其实吧,比如说调用one.room,在JVM那里也是翻译成了Student.room 来调用这个静态字段的.

后记

上面的内容大致介绍了static的情况,其实在写这篇博文的时候,帮助我理解了几个名词

栈,方法区,常量池,静态区,全局区,堆区 静态域它们之间是什么鬼??? 还有常量池到底在什么区的神经问题???

基础:
JAVA中,有六个不同的地方可以存储数据:

  1. 寄存器:最快的存储区,位于不同于其他存储区的地方——处理器内部。寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。
  2. 栈:存放基本类型的变量数据和对象的引用。位于通用RAM中,但通过它的“堆栈指针”可以从处理器哪里获得支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时候,JAVA编译器必须知道存储在堆栈内所有数据的确切大小和生命周期,因为它必须生成 相应的代码,以便上下移动堆栈指针。这一约束限制了程序的灵活性。
  3. 堆:一种通用性的内存池(也存在于RAM中),用于存放所以的JAVA对象。堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆进行存储分配比用堆栈进行存储存储需要更多的时间。
  4. 静态域:存放静态成员(static定义的) 。
  5. 常量池:存放字符串常量和基本类型常量(public static final)。 常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。
  6. 非RAM存储:硬盘等永久存储空间。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。

静态域也称为静态区,也称为全局区.用于存储静态字段和静态方法, 被方法区的类静态变量和静态方法名引用
上面的三个名词一下子解决了三个

关于方法区位于哪个位置,不同的JDK版本都有所不同,这个不用深究,和堆区在功能上分开来看就好了,不过JDK1.8上在堆区内,也是我学习的版本,目前这个时间段之前所有的图示都是基于此JDK版本画的

下面可以对比解释一下栈,堆,方法区这三个概念
【Java核心技术卷】理解static (内存图描述)_第3张图片
堆区:(JDK1.8版本 方法区在堆区)
存放线程操纵的数据(对象形式存放)

  1. 存储的全部是对象,每个对象包含一个与之对应的class信息–class的目的是得到操作指令
  2. jvm只有一个堆区(heap)被所有线程共享,堆区中不存放基本类型和对象引用,只存放对象本身。

栈区:

  1. 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象)。对象都存放在堆区中。
  2. 每个战中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。
  3. 栈分为3个部分:基本类型变量去,执行环境上下文,操作指令区(存放操作指令).

方法区:
存放线程所执行的字节码指令。

  1. 跟堆一样.被所有线程共享.方法区包含:所有的class和static变量.
  2. 方法区中包含的是在整个程序中唯一的元素.如class static 变量.

这里说明一下静态区位于方法区内

最后就是关于常量池了,常量池存放着String类型的字符串,还有一些final声明的常量,全局共享.

这写东西大致概念都了解啥情况了,具体内容的话,要写好多好多,而且内容很深很深,简单的理解就行了,比较深入的地方,等有一定基础了,向更高阶的内容迈进的时候,自然就学了.,目前写的这些东西,理解static就够了.

你可能感兴趣的:(Java核心技术)