美文网首页
java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中

java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中

作者: 许先森的许 | 来源:发表于2019-08-27 16:56 被阅读0次

    1、java中的变量与数据类型

    变量是一个容器,用来装什么的呢?装内存地址,这个内存地址对应的是内存中某个数据。
    那为什么这个容器不直接装这个数据更简洁呢?因为直接装数据的话,这个数据就无法被别的变量使用,无法复用就会导致很多不便。
    所以变量的内存分配可以看成两个不部分:1、变量在内存中的分配(“变量分配”) 2、变量所引用的数据在内存中的分配(“数据分配”)

    1.1、变量类型有:

    局部:在方法内声明的变量
    实例:在类中但在方法外声明并且没有static
    静态:声明为static的变量

    1.2、变量的数据类型有:

    1、原始数据类型 2、引用数据类型

    2、思考

    原始数据类型变量的“变量分配”和“数据分配”是在一起的(都在方法区或栈内存或堆内存,这里思考什么时候在方法区、什么时候在栈内存、什么时候在堆内存???)
    引用数据类型的“变量分配”和“数据分配”不一定是在一起的(什么情况是在一起的?什么情况不在一起?)

    3、例子:

    public class Fruit {
    
     private static int x = 10;
     static BigWaterMelon bigWaterMelon_1 = new BigWaterMelon(x);
    
     private int y = 20;
     private BigWaterMelon bigWaterMelon_2 = new BigWaterMelon(y);
    
    public static void main(String[] args) {
        Fruit fruit = new Fruit();
        int z = 30;
        BigWaterMelon bigWaterMelon_3 = new BigWaterMelon(z);
    
    
        new Thread() {
            @Override
            public void run() {
                int k = 100;
                setWeight(k);
            }
    
            void setWeight(int waterMelonWeight) {
                fruit.bigWaterMelon_2.weight = waterMelonWeight;
                System.out.printf(fruit.bigWaterMelon_2.weight + "");
            }
    
        }.start();
    }
    }
    
    class BigWaterMelon {
    
     int weight;
    
     BigWaterMelon(int weight) {
        this.weight = weight;
     }
    }
    
    image.png

    3.1、分析:

    栈:

    1、栈内存中按线程粒度来划分区域。

    比如划分为:主线程、new Thread线程、其他线程等等

    2、每个线程区域中又按方法粒度来划分区域。

    比如:主线程区域中划分了一块区域:main();new Thread线程中划分了两块区域:setWeight()、run()

    3、每块方法区域中包含其所有的局部变量。

    比如main()方法这块区域中包含局部变量:String[] args、Fruit fruit、int z = 30、BigWaterMelon bigWaterMelon_3
    这里可以看到String[] args、Fruit fruit、BigWaterMelon bigWaterMelon_3这三个局部变量在这里只存储了变量,而没有存放变量的数据,而int z = 30既存放了变量int z 也存放了变量的数据30。这就可以肯定上面的第一条结论“栈内存中,基本数据类型的变量和变量的数据是存放在一起的”,这里要注意:只是说存放在一起,但没说是一起在栈内存,也可能一起在堆内存或者方法区,继续往下分析。

    方法区:

    1、方法区中按class粒度来划分区域。(所以方法区存储的都是只加载一次的)

    比如:Fruit.class、BigWaterMelon.class、Fruit$1.class(这是个什么玩意?后面解释)

    2、在每块class区域中包含其所有的静态变量。(所以方法区存储的都是只加载一次的)

    比如:Fruit.class中包含static int x = 10、static BigWaterMelon bigWaterMelon_1。这里又出现了基本数据类型,和在栈内存中一样,基本数据类型的变量和变量的数据存放在一起,和栈内存中唯一不同的是,栈内存中是局部变量,而方法区中是静态变量。

    堆:

    1、堆内存中按实例和其所包含的非静态变量划分区域。

    比如:
    1、new String[] 对应的变量是栈内存中的 : String[] args;
    2、new BigWaterMelon()+int weight = 10 对应的变量是方法区中 :static BigWaterMelon bigWaterMelon_1;
    3、new BigWaterMelon()+int weight = 30 对应的变量是栈内存中 :BigWaterMelon bigWaterMelon_3;
    4、new Fruit()+int y = 20+BigWaterMelon bigWaterMelon_2 对应的变量是 栈内存中 :Fruit fruit;
    5、new BigWaterMelon()+int weight = 20 对应的变量是同在堆内存中的 : BigWaterMelon bigWaterMelon_2;
    6、new Fruit$1() 没有对应变量,因为它是匿名的,在方法区中存在它的类文件Fruit$1.class(这是个啥东西往下看)

    前面一直搞不明白Fruit$1.class这是个什么玩意,找编译后的文件看一下:

    image.png
    其实就是一个Thread类。。。只是因为我们用了匿名对象,所以给我们生成了一个这么个玩意,那如果我们把new Thread放在别的类中试试会怎么样,新建一个Test.class如图:
    image.png
    为了简介,我把Thread对象中所有东西都注释了。在编译后得到:
    image.png
    打开看看:
    image.png
    果然就是一个Thread类,所以匿名对象其实会生成一个class文件,类名就是由匿名对象存在的类名字后面加$和数字拼成。原谅我的基础辣鸡。。。
    好了,重新描述一下上面堆内存的第六条就可以这么说:
    6、new Fruit$1()(即new Thread()) 没有对应变量,因为它是匿名的,在方法区中存在它的类文件Fruit$1.class。
    这下就好理解了。
    我们在回头看Fruit$1.class文件,可以看到他有一个构造函数:
    image.png
    Fruit$1(Fruit paramFruit) {}
    所以在堆内存中的形式应该是new Fruit$1()(即new Thread())+Fruit paramFruit,其中Fruit paramFruit变量对应的实例就是堆中的第4条。

    3.2、结论

    3.2.1、“变量的分配”:

    局部变量在栈内存,静态变量在方法区,实例变量在堆内存。 也就是三个内存中都有变量。

    3.2.2、“数据的分配”:

    原始数据类型跟随自己的“变量分配”在一起,相亲相爱。
    引用数据类型在堆内存中。

    完毕。
    有不对的地方请指导。

    相关文章

      网友评论

          本文标题:java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中

          本文链接:https://www.haomeiwen.com/subject/zggeectx.html