Java中的值传递

部署运行你感兴趣的模型镜像

1.引子:变量的赋值

对于基本数据类型

int m = 1;
int n = 2;
System.out.println("m = " + m);
System.out.println("n = " + n);
n = m;
System.out.println("n = " + n);

输出
m = 1
n = 2
n = 1

赋的值就是变量值。

对于引用类型

class User{
    int a;
}

User u1 = new User();
u1.a = 1;
User u2 = u1;
System.out.println("u1中的a为" + u1.a + "," + "u2中的a为" + u2.a);
u2.a = 2;
System.out.println("u1中的a为" + u1.a + "," + "u2中的a为" + u2.a);


输出
u1中的a为1,u2中的a为1
u1中的a为2,u2中的a为2

赋的值是地址值。

有同学可能会对第二个有疑问,这里我来画个简陋的内存解析来帮助理解一下。

在这里插入图片描述

5行代码,new了一个User对象,存放在堆空间中,a的初始值为0.而u1这个局部变量存储在栈中,u1的值为User对象的地址值0x3336行代码,u1修改了a的值,即a变成17行代码,栈中来了一个u2,将u1的地址值赋给了u2,所以u2的值也为0x3339行代码,u2修改了a的值,即a变成2

2.值传递机制

首先要明确,这个是主要体现在方法的调用上,也就是针对于方法中的形参与传递给它的实参而言。

方法中形参的传递机制:值传递

(1) 如果参数是基本数据类型,实参传递给形参的是真实存储的数据值

(2) 如果参数是引用类型,实参传递给形参的是地址值

举个例子,交换 a a a b b b 的值,有如下一 s w a p swap swap函数

void swap(int a,int b){
    int t = a;
    a = b;
    b = t;
}

如果此时调用该函数,能起到交换作用吗?

int x = 1;
int y = 2;
swap(x,y);

答案是不会的!这里还是拿简陋的内存图来解析一下
在这里插入图片描述

可以看出, s w a p swap swap 交换的仅仅只是它自己方法体内的参数,而不是 x x x y y y ,因为 a a a b b b 只是实参 x x x y y y 的是一个拷贝值。方法结束之后,它们就会被回收掉。

如果我再问,下面的 s w a p swap swap 函数,能起到交换作用吗?

void swap(User a, User b){
    User t = a;
    a = b;
    b = t;
}
User u1 = new User();
User u2 = new User();
swap(u1,u2);

class User{
    
}

答案依然是不会!

在这里插入图片描述

可以看到,我一顿操作,蓝色箭头丝毫没有受到影响。

那要怎么才能完成交换呢?这时候回到引子里面的对于引用类型的变量赋值,能找到一些答案。

void swap(int[] array,int a,int b){
    int t = array[a];
    array[a] = array[b];
    array[b] = t;
}

这样的一个交换函数,就能起到交换作用了!

int[] h = {1,2};
swap(h,0,1);
System.out.println(h[0] + "," h[1]);

输出
2,1

在这里插入图片描述

也就是说,一个方法不能修改一个基本数据类型的参数,但可以修改一个引用类型所指向的对象的状态

即传递引用类型的实参的话,形参会获得该实参的地址值,我们可以通过修改形参以达到修改实参的目的。

3.有意思的思考题

(1)

public class Test{
    public static void main(String[] args){
        int a = 10;
        int b = 20;
        method(a,b);//调用method方法后,仅打印出a=100,b=200
        System.out.println("a="+a);
        System.out.println("b="+b);
    }
    //代码编写处
    public static void method(int a,int b){
        
    }
}

(2)

int[] arr = {1,2,3};
System.out.println(arr);
char[] c = {a,b,c};
System.out.println(c);

输出
第二行输出:________
第四行输出:________

答案

(1)

public static void method(int a,int b){
    System.out.println("a=" + a*10);
    System.out.println("b=" + b*10);
    System.exit(0);
}

(2)

a r r arr arr的地址值

a b c abc abc

4.参考资料

(1) 尚硅谷_Java零基础教程-java入门必备-适合初学者的全套完整版教程(宋红康主讲)

(2) java基本数据类型传递与引用传递区别详解


更多Java内容欢迎扫码关注我的公众号ACJavaBear,文章第一时间会发在上面。一起学Java吧
在这里插入图片描述

您可能感兴趣的与本文相关的镜像

Dify

Dify

AI应用
Agent编排

Dify 是一款开源的大语言模型(LLM)应用开发平台,它结合了 后端即服务(Backend as a Service) 和LLMOps 的理念,让开发者能快速、高效地构建和部署生产级的生成式AI应用。 它提供了包含模型兼容支持、Prompt 编排界面、RAG 引擎、Agent 框架、工作流编排等核心技术栈,并且提供了易用的界面和API,让技术和非技术人员都能参与到AI应用的开发过程中

<think>好的,用户想了解Java中的值传递原理和实现机制。首先,我需要确认自己对值传递的理解是否正确。Java中确实只有值传递,无论是基本类型还是对象引用。当传递基本类型时,传递的是值的副本;当传递对象时,传递的是对象引用的副本。这意味着在方法内部修改引用指向的对象会影响原对象,但修改引用本身不会影响原引用。 接下来,我需要结合用户提供的引用内容。用户引用了关于反射机制、值传递与引用传递的例子、形参传递机制以及TransmittableThreadLocal的内容。其中引用[2]和[3]直接相关,特别是引用[2]中的例子展示了基本类型值传递,修改形参不影响实参。引用[3]提到值传递机制,可能与参数传递的底层实现有关。 用户可能存在的疑问是为什么对象作为参数传递时,修改对象内容会影响原对象,但重新赋值引用却不会。需要解释清楚传递的是引用的副本,副本和原引用指向同一个对象,所以修改对象属性会影响原对象,但修改副本引用指向新对象不会影响原引用。 另外,用户可能混淆了值传递和引用传递的概念,需要明确Java中没有引用传递,只有值传递,包括对象引用的传递也是值传递的一种形式。需要举例说明基本类型和对象类型的不同表现,并解释底层原理,如栈内存中的副本机制。 可能还需要提到内存模型,比如栈和堆的区别,基本类型存储在栈,对象实例在堆,引用变量在栈中存储地址。传递时复制的是栈中的值,即地址的副本,因此操作同一对象实例但引用变量本身是独立的。 最后,结合用户提供的引用,引用[2]的例子可以用于说明基本类型值传递,而引用[3]中的形参传递机制可以进一步支持值传递的解释。可能需要强调无论参数类型如何,传递的都是值的副本,只是这个值可能是基本类型的数值或对象的引用地址。</think>### Java 值传递原理及实现机制 #### 一、基本概念 Java **严格采用值传递机制**,这意味着方法调用时传递的始终是变量的副本,而非变量本身。无论是基本数据类型还是对象引用类型,传递的都是值的拷贝[^2][^3]。 #### 二、实现原理 1. **基本数据类型传递** - 传递的是变量的**值副本**,方法内修改形参不影响原始变量。 - 例如: ```java int x = 10; void modify(int num) { num = 20; } // 调用 modify(x) 后,x 仍为 10 ``` 2. **对象引用类型传递** - 传递的是对象引用的**地址值副本**,形参和实参指向同一对象。 - 若通过形参修改对象属性,会影响原始对象;但若修改形参的引用指向,不影响原始引用。 - 示例: ```java class MyObj { int val; } MyObj obj = new MyObj(); void modifyRef(MyObj param) { param.val = 20; // 修改对象属性,原始对象受影响 param = new MyObj(); // 修改形参引用指向,原始引用不受影响 } ``` #### 三、内存模型解释 - **栈内存**:存储基本数据类型值和对象引用地址。 - **堆内存**:存储对象实例。 - 值传递过程中,栈内存中的值(基本类型数值或引用地址)会被复制到新的栈帧中。 #### 四、典型场景验证 1. **基本类型示例** 引用[^2]中的代码: ```java public static void changeValue(int num) { num = 20; } ``` 调用后原始变量不变,验证了值副本机制。 2. **对象类型示例** ```java void updateArray(char[] arr) { arr[0] = 'X'; // 修改堆内存中的对象 arr = new char[5]; // 修改栈中的引用副本 } ``` 执行后原始数组的第一个元素会被修改,但数组引用不变。 #### 五、与引用传递的对比 - **值传递**:传递副本,副本与原数据独立(但对象引用副本与原引用指向同一对象)。 - **引用传递**(Java不存在):直接操作原始变量,如C++的引用参数。 #### 六、特殊场景扩展 多线程环境下,父子线程间的值传递可通过`TransmittableThreadLocal`实现,其本质仍是基于值传递机制的特殊封装[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值