成员变量和局部变量在内存中的变化

简介: 今天我们从成员变量和局部变量来加深印象,彻底弄懂成员变量和局部变量在内存中的变化

成员变量和局部变量在内存中的变化

WangScaler: 一个用心创作的作者。

声明:才疏学浅,如有错误,恳请指正。

在前边类的加载机制以及类、对象初始化的详细过程已经讲了类的加载机制,以及在Java易错点1讲解过变量在内存中的变化,那么今天我们从成员变量和局部变量来继续加深印象,彻底把知识装入脑袋中。如果你看下文不是很清楚的话,一定得先看上边的两篇文章。

成员变量和局部变量的区别

成员变量

  • 定义在类中
  • 存在于堆内存中
  • 有默认初始值
  • 随对象的创建而创建,随对象消失而消失

局部变量

  • 定义在方法中
  • 存在于栈内存中
  • 无默认初始值
  • 方法入栈而创建,方法出栈而消失

注意:使用变量遵循就近原则,类中static修饰的变量也叫类变量。

示例代码

package com.wangscaler.variable;
​
/**
 * @author WangScaler
 * @date 2021/8/2 10:56
 */
​
public class VariableMain {
    static int i;
    int j;
    int k;
​
    {
        int j = 1;
        j++;
        i++;
        k++;
    }
​
    public void add(int j) {
        i++;
        j++;
        k++;
        
    }
​
    public static void main(String[] args) {
        VariableMain variableMain = new VariableMain();
        VariableMain variableMain1 = new VariableMain();
        variableMain.add(100);
        variableMain.add(200);
        variableMain1.add(300);
        System.out.println(variableMain.i + "--------------wangscaler------------------" + variableMain1.i);
        System.out.println(variableMain.j + "--------------wangscaler------------------" + variableMain1.j);
        System.out.println(variableMain.k + "--------------wangscaler------------------" + variableMain1.k);
    }
}

解析

先来看看这三个打印的结果是啥。

5--------------wangscaler------------------5
0--------------wangscaler------------------0
3--------------wangscaler------------------2

那么接下来看看到底是怎么执行的。

  • 1、根据类的加载机制以及类、对象初始化的详细过程我们知道main方法所在的类会先加载。

    • 加载时会先加载静态变量并赋初值。所以如果我们把main清空,不创建VariableMain对象,只打印打印i的值,会是0。
    • 我们知道jdk1.8之后,将常量池和静态变量由永久代转移至堆内存中,所以应该是下图。

image-20210802134410359.png

  • 2、创建对象variableMain

    • int j; int k;此时非静态变量会初始化

      image-20210802135417611.png

    • 代码块初始化int j = 1;,因为j在代码块中生成的,属于局部变量,固存在栈内存中。

    image-20210802135631702.png

-   `j++;`依据就近原则,所以此时j依然是栈内存中的j.


    ![image-20210802135929499.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/03990133847840a989273fea610a695b~tplv-k3u1fbpfcp-watermark.image)
-   `i++; k++;`此时代码块没有这两个变量,那么调用的就是成员变量,所以堆内存中的i、j的值将变化。


    ![image-20210802140138588.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4a7e8a2d49514d2584dd03c7d895b4e7~tplv-k3u1fbpfcp-watermark.image)
    代码块执行完毕,栈内存中的j会随着`<init>`调用完毕而消失,这里不再画出。
  • 3、创建对象variableMain1

    步骤基本和2相同,唯一需要注意的是,i因为是类变量是共享的,所以如为下图所示i的值会在之前值的基础上继续增加。

    image-20210802140740926.png
    同样当代码块执行完毕,栈内存中的j会随着<init>调用完毕而消失,这里不再画出。

  • 4、variableMain.add(100);此时方法的调用j是形参即局部变量,根据就近原则add方法里的j都是局部变量。所以执行完之后如下图:

    image-20210802141748478.png

add方法执行完,会在栈内存中消失。

  • 5、variableMain.add(200);同上:

    image-20210802142020942.png

  • 6、variableMain1.add(300);

    image-20210802142131004.png

  • 7、结果

    根据堆内存的值,不难看出我们的结果是什么了。

注意

  • 1、类变量的调用,虽然上述的例子variableMain.i 可以正常执行,但是不建议这样写,如果你安装了代码检查的插件,他是会报错的,我们知道类变量是唯一的,所以我们调用时,应该类.变量,即VariableMain.i
  • 2、像上述的例子,因为我们j都是局部变量,所以堆内存中的j一直没变化。当局部变量和成员变量共存时,可以使用this.j来调用成员变量。
  • 3、尽量给成员变量赋初值,不要依赖编译器,上述的例子就没有赋初值。
目录
相关文章
|
4月前
|
存储 缓存 Java
Java面试题:解释Java中的内存屏障的作用,解释Java中的线程局部变量(ThreadLocal)的作用和使用场景,解释Java中的锁优化,并讨论乐观锁和悲观锁的区别
Java面试题:解释Java中的内存屏障的作用,解释Java中的线程局部变量(ThreadLocal)的作用和使用场景,解释Java中的锁优化,并讨论乐观锁和悲观锁的区别
51 0
|
4月前
|
并行计算 算法 安全
Java面试题:解释Java内存模型的内存屏障,并讨论其对多线程并发的影响,解释Java中的线程局部变量(ThreadLocal)的工作原理,解释Java中的ForkJoinPool的工作原理
Java面试题:解释Java内存模型的内存屏障,并讨论其对多线程并发的影响,解释Java中的线程局部变量(ThreadLocal)的工作原理,解释Java中的ForkJoinPool的工作原理
42 0
|
6月前
|
存储 编译器 C语言
C陷阱:数组越界遍历,不报错却出现死循环?从内存解析角度看数组与局部变量之“爱恨纠葛”
在代码练习中,通常会避免数组越界访问,但如果运行了这样的代码,可能会导致未定义行为,例如死循环。当循环遍历数组时,如果下标超出数组长度,程序可能会持续停留在循环体内。这种情况的发生与数组和局部变量(如循环变量)在内存中的布局有关。在某些编译器和环境下,数组和局部变量可能在栈上相邻存储,数组越界访问可能会修改到循环变量的值,导致循环条件始终满足,从而形成死循环。理解这种情况有助于我们更好地理解和预防这类编程错误。
139 0
|
存储 C语言
深入理解C语言结构体成员变量内存分配
深入理解C语言结构体成员变量内存分配
100 0
|
存储 编译器 C++
临时确保局部变量使用的内存空间
临时确保局部变量使用的内存空间
64 0
|
人工智能 Java
变量的值传递,地址引用(和对象成员变量、局部变量创建和初始化的内存机制)
变量的值传递,地址引用(和对象成员变量、局部变量创建和初始化的内存机制)
177 0
变量的值传递,地址引用(和对象成员变量、局部变量创建和初始化的内存机制)
|
存储 程序员 C++
局部变量,静态局部变量,全局变量,静态全局变量在内存中的存放区别(转)
我们先来看内存中的几大区:  内存到底分几个区? 下面有几种网上的理解,我整理一下: 一:  1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
952 0
|
存储 程序员 编译器
全局、静态、局部变量的内存分配
在标准的C中,变量大概可以分为全局变量(用extern修饰),静态变量(用static修饰),局部变量三中类型.      在内存中用于存储变量的空间也可以分为堆区、栈区、全局区(静态区)。
1161 0
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
372 0