java 函数形参传值和传引用的区别

本文解析了Java中方法调用时的传值机制,包括基本数据类型的传值与对象类型的传引用区别,并通过具体实例展示了如何影响实参的值或状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java方法中传值和传引用的问题是个基本问题,但是也有很多人一时弄不清。


  (一)基本数据类型:传值,方法不会改变实参的值。

  public class TestFun {
  public static void testInt(int i){
  i=5;
  }
  public static void main(String[] args) {
  int a=0 ;
  TestFun.testInt(a);
  System.out.println("a="+a);
  }
  }

  程序执行结果:a=0 。


  (二)对象类型参数:传引用,方法体内改变形参引用,不会改变实参的引用,但有可能改变实参对象的属性值。

  举两个例子:

  (1)方法体内改变形参引用,但不会改变实参引用 ,实参值不变。

  public class TestFun2 {
  public static void testStr(String str){
  str="hello";//型参指向字符串 “hello”
  }
  public static void main(String[] args) {
  String s="1" ;
  TestFun2.testStr(s);
  System.out.println("s="+s); //实参s引用没变,值也不变
  }
  }

  执行结果打印:s=1


  (2)方法体内,通过引用改变了实际参数对象的内容,注意是“内容”,引用还是不变的。

        import java.util.HashMap;
        import java.util.Iterator;
        import java.util.Map;
        import java.util.Set;

        public class Test {
public void a(Map a,String b)
{
a.put("test", b);
}

public void b()
{
Map a = new HashMap();
a.put("test", "a");
String b = "b";
//printMap(a);
a(a,b);
printMap(a);
}

public void printMap(Map a)
{
Set set = a.entrySet();
Iterator it = set.iterator();
while(it.hasNext())
{
Map.Entry e = (Map.Entry)it.next();
System.out.println("Key:"+e.getKey()+" Value:"+e.getValue());

}
}

public static void main(String avgs[])
{
Test t = new Test();
t.b();
}
}


  执行结果,打印:Key:test Value:b 。可见在方法a()内改变了实参的内容。


  (3)第二个例子是拿map举例的,还有经常涉及的是 StringBuffer :

  public class TestFun4 {
  public static void testStringBuffer(StringBuffer sb){
  sb.append("java");//改变了实参的内容
  }
  public static void main(String[] args) {
  StringBuffer sb= new StringBuffer("my ");
  new TestFun4().testStringBuffer(sb);
  System.out.println("sb="+sb.toString());//内容变化了
  }
  }


  执行结果,打印:sb=my java 。

  所以比较参数是String和StringBuffer 的两个例子就会理解什么是“改变实参对象内容”了。


  总结:

  第一:java方法基本数据类型是传值,对象类型传引用,这是千真万确的。

  第二:当参数是对象时,无论方法体内进行了何种操作,都不会改变实参对象的引用。

  第三:当参数是对象时,只有在方法内部改变了对象的内容时,才会改变实参对象内容。

<think>嗯,用户问的是函数调用引用调用,我得先理清楚这两个概念的区别应用场景。先从基本定义开始,调用是把实际参数的复制一份给形参,而引用调用则是递参数的地址,让形参实参指向同一块内存。 接下来要考虑用户的背景。可能是刚开始学编程的新手,或者对函数调用机制不太清楚的人。他们可能在实际编程中遇到了问题,比如为什么修改了参数的但外部变量没变,或者相反的情况。需要举例说明,这样更容易理解。 得注意使用中文,同时按照系统级指令处理数学公式,但这里可能涉及代码示例,所以可能需要调整。不过用户的问题主要是编程概念,应该用代码例子来解释更直观。比如用C++或Python的例子,但要注意不同语言的参方式可能不同,比如Python中参数递是对象引用,这点可能需要说明。 另外,用户可能想知道两种调用方式的优缺点。比如调用不会改变原始数据,安全性高,但复制大数据结构时有性能问题。引用调用可以高效递大对象,但可能意外修改原始数据。这里需要强调副作用的问题。 还要注意结构清晰,分步骤讲解。先分别解释两种调用方式,再对比差异,最后给出适用场景。可能需要使用比喻,比如就像给朋友发文档的复印件,而引用则是给文档的链接,朋友修改会影响原文档。 需要检查是否有常见的误解。比如有人认为Java引用调用,但实际上Java调用,递的是对象的引用副本。这点可能需要澄清,但用户的问题可能不涉及具体语言,所以保持一般性解释更好。 最后总结两者的选择标准,帮助用户根据需求决定使用哪种方式。确保回答真实可靠,避免错误,比如明确指出大部分现代语言默认,但提供引用调用的机制如指针、引用类型等。</think>函数调用引用调用是编程中两种重要的参数递机制,它们的核心区别在于对原始数据的影响方式。以下从原理、特点应用场景逐步分析: 1. **调用 (Call by Value)** - **执行过程**: - 函数调用时,系统将实参的复制一份副本递给形参 $$ \text{形参} = \text{实参的副本} $$ - 函数内部对形参的修改不会影响原始实参 - **示例代码**: ```python def modify(num): num = 10 # 仅修改局部副本 x = 5 modify(x) print(x) # 仍输出5 ``` - **特点**: - 数据隔离:原始数据安全 - 内存消耗:需要复制数据副本 - 适用场景:基本数据类型、小型数据结构 2. **引用调用 (Call by Reference)** - **执行过程**: - 函数接收实参的内存地址引用 $$ \text{形参} \equiv \text{实参内存地址} $$ - 函数内对形参的修改直接影响原始数据 - **示例代码**: ```cpp void modify(int &ref) { ref = 10; // 直接修改原始数据 } int main() { int x = 5; modify(x); cout << x; // 输出10 } ``` - **特点**: - 数据联动:直接操作原始数据 - 内存效率:无数据复制开销 - 适用场景:大型对象、需要双向数据递 3. **关键差异对比** | 特征 | 调用 | 引用调用 | |---------------|-----------------------|-----------------------| | 数据副本 | 创建独立副本 | 共享原始数据 | | 内存占用 | 可能较高(大数据时) | 固定开销 | | 副作用 | 无 | 可能产生预期外修改 | | 典型语言实现 | C基本类型、Python不可变对象 | C++引用、Python可变对象操作 | 4. **混合机制注意事项** - Java/C#等语言的"对象递"本质是对象引用 - Python中不可变对象(如整数、字符串)表现为特性,可变对象(如列表)表现为引用特性 **应用建议**: - 优先使用调用确保数据安全 - 当需要高效处理大型数据或需要返回多个时采用引用调用 - 现代语言常通过`const引用`等机制兼顾效率与安全性 理解这两种机制的区别,可以帮助开发者更好地控制程序状态,避免意外的数据修改,并优化内存使用效率。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值