• Java 基础 --- Java变量储存机制及参数传递


    JVM内存机制

    在这里插入图片描述

    在这里插入图片描述

    Primitive type的储存和值传递

    primitive type的储存

    • primitive type的局部变量是储存在JVM stack上, 首先JVM创建一个名为A的变量, 存在于局部变量表中,然后去栈中查找是否存有字面量值为10的内容,如果有就直接把A指向这个地址. 如果没有,JVM会在栈中开辟一块空间来存储10这个内容.
    • 当写下 int A = 10 时:
      在这里插入图片描述
    • 当写下 int A = 10, int B = 10 时:
      在这里插入图片描述
    • int A = 10, int B = 10, B = 20;
      在这里插入图片描述

    primitive type的值传递

    • 如下图,在执行main方法时,JVM会在栈顶加进一个栈帧,此栈帧包括一个A=10的变量。在执行passPrimitive方法时,JAM会再加入一个新的栈帧,此栈帧包括一个B=10的变量,当执行B=100时,在passPrimitive栈帧中的B值会被改变,但在main栈帧中的A值不会被改
      在这里插入图片描述
    • Before: A is 10
    • B is 100
    • After: A is 10

    Reference Type的储存和值传递

    Reference Type的储存

    • reference包括除基础类型之外的其他所有类型,变量中储存的时一个引用(在栈中存一个可以指向heap的引用),具体过程如下
      在这里插入图片描述

    Reference Type的传递

    • 会改变实参
      在这里插入图片描述
    • Before: S1’ID is 100
    • In The method: S1’ID is 200
    • After: S1’ID is 200
    • 当执行第21行(Student s1 = new Student())时
      在这里插入图片描述
    • 当执行第24行时(进入Test方法)
      在这里插入图片描述

    总结:

    • 在Java中没有引用传递,只有值传递。在Java中“值”的概念分为两种,一个是基础类型的实际数值,一个是引用,但是对于任何一种变量Java都拿不到地址(引用变量只是储存的是引用, 但是变量本身的地址是拿不到的, 也就是说Java中对对象的引用本身做不了任何操作,比如替换成另外一个引用)所以不存在引用传递。反之,在C++/C中对于任何一个变量(基础变量,类,指针变量等)除了可以拿到变量里的值以外还可以拿到变量的地址,所以有值传递,引用传递,指针传递之分

    关于包装类的参数传递问题: Integer as example

    • 虽然所有的包装类都是引用传递,但是在函数中传递包装类并不能改变实参
    • 因为所有的包装类都是不可变类, 也就是用final修饰, 比如final int value. 所以当对象被重新赋值时,会生成新的对象
    • 根据Integer的缓存机制,如果在-128-127之间 就从常量池中获取一个Integer对象返回;如果不在范围内 会new Integer(value)返回
    public class ValuePassing {
    	
    	public static void fun1(Integer i) {
    		System.out.println("在fun1中赋值前i的地址是: " + System.identityHashCode(i));
    		i = 10; //从常量池中获取一个Integer对象,或者new Integer(value)
    		//赋值之后,地址发生改变
    		System.out.println("在fun1中赋值后i的地址是: " + System.identityHashCode(i));
    	}
    	
    	public static void main(String[] args) {
            Integer i = 5;
            System.out.println("在main中i的地址是: " + System.identityHashCode(i));
            fun1(i);
            
            i = 20;
            //赋值之后,地址发生改变
            System.out.println("在main中i重新赋值之后的地址是: " + System.identityHashCode(i));
        }
    }
    
    output:
    在main中i的地址是: 1072591677
    在fun1中赋值前i的地址是: 1072591677
    在fun1中赋值后i的地址是: 1523554304
    在main中i重新赋值之后的地址是: 1175962212
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    关于缓存:

    public class ValuePassing {
    	
    	public static void fun1(Integer i, Integer j) {
    		System.out.println("在fun1中赋值前i的地址是: " + System.identityHashCode(i));
    		System.out.println("在fun1中赋值后j的地址是: " + System.identityHashCode(j));
    		//对i和j同时赋予一样的值后(在-128-127之间),地址一样
    		i = 10; 
    		j = 10;
    		System.out.println("-----------------------------------------------");
    		System.out.println("在fun1中赋值后i的地址是: " + System.identityHashCode(i));
    		System.out.println("在fun1中赋值后j的地址是: " + System.identityHashCode(j));
    	}
    	
    	public static void main(String[] args) {
            Integer i = 5;
            Integer j = 20;
            System.out.println("在main中i的地址是: " + System.identityHashCode(i));
            System.out.println("在main中j的地址是: " + System.identityHashCode(j));
            System.out.println("-----------------------------------------------");
            fun1(i, j);
        }
    }
    
    output:
    在main中i的地址是: 1072591677
    在main中j的地址是: 1523554304
    -----------------------------------------------
    在fun1中赋值前i的地址是: 1072591677
    在fun1中赋值后j的地址是: 1523554304
    -----------------------------------------------
    在fun1中赋值后i的地址是: 1175962212
    在fun1中赋值后j的地址是: 1175962212
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    public class ValuePassing {
    	
    	public static void fun1(Integer i, Integer j) {
    		System.out.println("在fun1中赋值前i的地址是: " + System.identityHashCode(i));
    		System.out.println("在fun1中赋值后j的地址是: " + System.identityHashCode(j));
    		
    		//不在-128-127之间地址则不一样
    		i = 1000; 
    		j = 1000;
    		System.out.println("-----------------------------------------------");
    		System.out.println("在fun1中赋值后i的地址是: " + System.identityHashCode(i));
    		System.out.println("在fun1中赋值后j的地址是: " + System.identityHashCode(j));
    	}
    	
    	public static void main(String[] args) {
            Integer i = 5;
            Integer j = 20;
            System.out.println("在main中i的地址是: " + System.identityHashCode(i));
            System.out.println("在main中j的地址是: " + System.identityHashCode(j));
            System.out.println("-----------------------------------------------");
            fun1(i, j);
        }
    }
    
    output:
    在main中i的地址是: 1072591677
    在main中j的地址是: 1523554304
    -----------------------------------------------
    在fun1中赋值前i的地址是: 1072591677
    在fun1中赋值后j的地址是: 1523554304
    -----------------------------------------------
    在fun1中赋值后i的地址是: 1175962212
    在fun1中赋值后j的地址是: 918221580
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    DVWA-SQL Injection(SQL注入)
    神经网络的训练与测试,神经网络显著性检测
    这就是艺术「GitHub 热点速览 v.22.25」
    react设置代理
    【指针详解】(上)看一遍就会❗❗❗家人们冲❗
    Spark 离线开发框架设计与实现
    问题记录|线上问题诊断大逃杀|docker环境中arthas启动不起来的问题解决
    Zookeeper入门(一)
    spring cloud之负载均衡
    代码随想录算法训练营第二天 | 242. 有效的字母异位词、349. 两个数组的交集、1. 两数之和
  • 原文地址:https://blog.csdn.net/weixin_38803409/article/details/126558594