java中的参数传递

目录

1.说明

2.基础数据类型

3.基础数据类型的包装类

4.对象,数组,集合


1.说明

        java中只有值传递,当作为参数传递时,传递的是基础数据类型的值的副本,及引用类型的引用的副本。

2.基础数据类型

①基础数据类型的内存分配

        基础数据类型是在栈内存中分配,当你声明一个基本数据类型变量时,会直接在栈上分配空间,栈内存用于存储局部变量和方法调用时的临时变量,这种内存的分配和释放速度是非常快的。

②栈的说明

        栈:栈是一种数据结构,遵循后进先出原则,其元素的插入和删除都发生在同一端,这个端被称为栈顶,也就是说最新加入的元素总是最先被移除,从而实现了后进先出的特性。

        实际应用:

                函数调用:当一个函数调用时,系统会将上下文信息保存在栈中,当函数执行完毕,栈顶的信息会被弹出,恢复之前的状态。

                递归:每次递归调用都会将当前状态保存到栈中,以便在递归调用结束能够恢复之前的状态。

③将基础类型作为参数传递至方法中

         当一个基础数据类型作为参数传递至方法中时,传递的是值的副本。

int a = 1;
int b = 1;

 比如说将a作为参数传递到方法中,会将和a一样值的副本,即b传递给方法,a和b在内存中是这样体现的。

首先是内存分配,每当一个方法被调用时,JVM 会为该方法创建一个新的栈帧。a和b作为基础数据类型会存储在栈中,当方法执行到 int a = 1; 时,JVM 在当前栈帧中为 a 分配内存(通常是 4 字节,因为 int 类型占用 4 字节),并将值 1 存储在这个内存位置。当调用方法时,会创建b,JVM 为 b 分配另一个 4 字节的内存空间,并将值 1 存储在这个位置。a和b各自占用各自的内存空间,所以,在方法中修改参数的内容,实际修改的b的内容,方法外面的a的内容不受影响。布局如下:

+-------------------+
|   返回地址        |  ←(方法结束后返回的地址)
+-------------------+
|   b               |  ← b 的值(4 字节)
|   ----------------- |
|   a               |  ← a 的值(4 字节)
+-------------------+
(栈帧顶部)


④示例

    @Test
    public void testParam1(){
        int num1 = 1;
        changeNum(num1);
        System.out.println(num1);

    }

    public void changeNum(int num){
        num = 23;
    }

输出结果为1

3.基础数据类型的包装类

①包装类的不可变性

        Java中的基础数据类型的包装类(如 IntegerBooleanDouble 等)都是不可变的(immutable)。

        不可变类是指一旦创建对象后,其状态(即其属性值)不能被改变。对于不可变类,所有的方法都不会修改对象本身,而是返回一个新的对象。由于不可变性,这些包装类在多线程环境中是安全的,不会出现数据竞争的问题。

  • intInteger
  • booleanBoolean
  • charCharacter
  • byteByte
  • shortShort
  • longLong
  • floatFloat
  • doubleDouble

②将基本数据类型的包装类传递至方法中

将基础数据类型的包装类传递至方法中时,传递的是引用的副本

Integer a = 1;
Integer b = 1;

 比如说将a传递至方法中,会将和a一样的值的副本b传递至方法中。a和b在内存中是这样体现的。

当您将一个整数值(如 1)赋给 Integer 类型时,Java 会进行装箱,将基本类型 int 转换为 Integer 对象。Integer 对象会分配到堆内存中,而不是栈内存。JVM 会在堆中创建一个 Integer 对象来表示值 1。对于小整数(通常是 -128 到 127 范围内的数字),Java 会利用缓存机制,即对这些常用的 Integer 对象进行复用(称为“缓存”)。因此a和b在栈上是两个对象,指向堆内存中的同一个对象。如果在方法中修改b的内容,如修改为2,则栈内存中的b会指向堆内存中的2,不会影响a的内容。内存布局如下:

堆内存

+-------------------+
|   Integer Object  |  ← (堆内存中存储的 Integer 对象)
|   value = 1       |
+-------------------+
栈内存

+-------------------+
|   栈内存          |
+-------------------+
|   a  → (堆中的 Integer 对象) |
|   b  → (堆中的 Integer 对象) |
+-------------------+

    @Test
    public void testParam2(){
        Integer num1 = 2;
        changeNum1(num1);
        System.out.println(num1);

    }

    public void changeNum1(Integer num){
        num = 24;
    }
输出结果为2

4.对象,数组,集合

将对象,数组或者集合传递至方法中时,传递的也是引用的副本,方法外的变量和方法内的参数都是执行同一个堆内存中的对象。在方法中对参数内容进行修改时,会直接修改堆内存中的内容,方法外的变量的内容也会随之改变。如果你在方法中修改了参数的引用,方法外的变量的内容则不受影响。

在方法中直接修改内容的示例

    @Test
    public  void testBean(){
        SysConfig sysConfig = new SysConfig();
        sysConfig.setConfigId(123L);
        setBean(sysConfig);
        System.out.println(sysConfig.getConfigId());

    }

    public void setBean(SysConfig sysConfig){
        // sysConfig = new SysConfig();
        sysConfig.setConfigId(258L);
    }
输出结果为258

在方法中修改引用的示例

    @Test
    public  void testBean2(){
        SysConfig sysConfig = new SysConfig();
        sysConfig.setConfigId(123L);
        setBean2(sysConfig);
        System.out.println(sysConfig.getConfigId());

    }

    public void setBean2(SysConfig sysConfig){
        sysConfig = new SysConfig(); 在堆内容中创建了一个对象,将参数的引用指向这个对象,修改了参数的引用
        sysConfig.setConfigId(258L);
    }

输出结果为123

你可能感兴趣的:(java常用,java,jvm,开发语言)