Java:值传递和引用传递

郎家岭伯爵 2025年08月19日 12次浏览

前言

今天遇到一个关于 Java 引用导致的 Bug,这个问题其实是一个高频的面试问题,比较考验我们对 Java 中“对象类型传递”的理解。这个问题还是比较基础的,稍微记录一下。

实现

理论部分

首先我们需要明确:Java 中所有的参数传递都是值传递

  1. 基本数据类型直接传递的是值,这很直观。Java 中有 8 种基本数据类型,分别是4种整数型 byte、short、int、long,2种浮点型 float、double,1种布尔型 boolean,1种字符型 char。

需要注意的是:8种基本数据类型的包装类属于对象类型,因此传递的也是内存地址。但由于包装类全部被 final 修饰,是不可变对象,传递后的值无法修改原对象,只会重新赋值引用,类似于 new 了一个新的对象。因此修改传递后的值并不会影响原来的值。

  1. 针对对象类型(例如数组、String、实体类等等),传递的是对象的内存地址的值。这区别于我们所理解的具体的值,对象的“值传递”针对的是它的内存地址。这也就是我们在对传递后的变量进行修改时会影响原变量的值的根本原因。
数据类型 关键字 大小(字节) 取值范围/描述 默认值 包装类 典型应用场景
字节型 byte 1 -128 ~ 127 0 Byte 文件读写、网络传输(节省空间)
短整型 short 2 -32,768 ~ 32,767 0 Short 兼容历史代码或特定硬件接口
整型 int 4 -2³¹ ~ 2³¹-1 (约±21亿) 0 Integer 循环计数、日常数值计算
长整型 long 8 -2⁶³ ~ 2⁶³-1 0L Long 时间戳、大整数(如全球人口数)
单精度浮点型 float 4 约6-7位有效数字 0.0f Float 科学计算(牺牲精度换取速度)
双精度浮点型 double 8 约15位有效数字 0.0d Double 默认浮点计算(避免用于精确货币计算)
字符型 char 2 Unicode字符 (0 ~ 65,535) '\u0000' Character 文本处理、单个字符存储
布尔型 boolean 无明确大小 true/false false Boolean 逻辑判断、状态标志

实践部分

基本数据类型的包装类

一段示例代码:

package org.example.test;

import java.util.Arrays;

/**
 * @author 郎家岭伯爵
 */
public class Test2 {
    public static void main(String[] args) {

        Integer i1 = 1000;
        Integer i2 = i1;
        // 此时i1 和 i2 指向同一个对象
        System.out.println("i2:" + i2 + ";i1==i2:" + (i1 == i2));

        // 对象的赋值操作,会重新创建一个对象,i1 和 i2 指向不同的对象
        i1 = i1 + 10;
        i2 = i2 + 10;
        System.out.println("i2:" + i2 + ";i1==i2:" + (i1 == i2));
    }
}

输出:

i2:1000;i1==i2:true
i2:1000;i1==i2:false

对象类型

一段示例代码:

package org.example.test;

import java.util.Arrays;

/**
 * @author 郎家岭伯爵
 */
public class Test2 {
    public static void main(String[] args) {
        double[][] d = new double[][]{{1, 2, 3}};
        System.out.println("【原始数组】--- " + Arrays.deepToString(d));

        // 数组复制,修改d1[0],d[0]不会改变
        double[] d1 = Arrays.copyOf(d[0], d[0].length);
        for (int i = 0; i < d1.length; i++) {
            d1[i] = d1[i] + 5;
        }
        System.out.println("【Arrays.copyOf()】--- " + Arrays.deepToString(d));

        // 引用数据类型的赋值,只是复制了引用,修改d2[0],d[0]也会改变
        double[] d2 = d[0];
        for (int i = 0; i < d2.length; i++) {
            d2[i] = d2[i] + 5;
        }
        System.out.println("【d2 = d[0]】--- " + Arrays.deepToString(d));
    }
}

输出:

【原始数组】--- [[1.0, 2.0, 3.0]]
【Arrays.copyOf()】--- [[1.0, 2.0, 3.0]]
【d2 = d[0]】--- [[6.0, 7.0, 8.0]]

从这段代码中可以很清楚地看到在引用数据类型的传递中,对传递后对象的修改会影响到原对象。

总结

今天遇到一个 Java 中由于对“值传递”和“引用传递”有误解而导致的 Bug,这是一个 Java 中的比较基础的知识点,需要注意的是基本数据类型的包装类的“值传递”用法。稍微记录一下,加深印象。