当前位置: 首页 > news >正文

java 的参数传递

一、疑惑引入

首先,我们从一个例子来引出这个问题:

public static void main(String[] args) throws IOException {List<String> mockList = Lists.newArrayList("a", "b");System.out.println("1: " + mockList);List<String> result = change(mockList);System.out.println("3: " + mockList);System.out.println("4: " + result);
}
public static List<String> change(List<String> input){List<String> result = input.stream().sorted(Comparator.comparing(String::valueOf).reversed()).collect(Collectors.toList());System.out.println("2: " + result);return result;
}

请问,1,2,3,4 处分别输出的应该是什么?
答案是:

1: [a, b]
2: [b, a]
3: [a, b]
4: [b, a]

看到这里,同学对 1,2,4 的结果肯定是不会有疑问,可能会有一部分同学会对 3 的输出有些疑问,change方法不是对序列进行了倒排,为啥3 处mockList 的序列没变,如果有这个疑问的同学,那么你有必要要认真看下本文;
常见大家理解的误区可能有以下几点:

  1. 值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传递。如果是个引用,就是引用传递。
  2. Java是引用传递。
  3. 传递的参数如果是普通类型,那就是值传递,如果是对象,那就是引用传递

二、概念理解

首先,要理解这个问题,我们先来了解下几个概念

2.1、形参、实参

在编程中,参数(parameters)是指在函数定义中声明的占位符,用于接收传递给函数的值。

  • 形参(formal parameters)是函数定义中使用的参数名称,它们在函数定义时被声明。
  • 实参(actual parameters)是在函数调用时传递给函数的实际值。
    具体来说,形参是函数定义时使用的变量名,用于表示函数内部使用的值。它们在函数定义的括号内列出,并且可以有一个或多个。形参是函数内部的局部变量,只在函数内部可见和使用。
    下面是一个示例函数定义,其中x和y是形参:
def add_numbers(x, y):sum = x + yreturn sum

在这个例子中,add_numbers函数接受两个形参x和y,并返回它们的和。
实参是在函数调用时传递给函数的具体值。它们是实际用于执行函数操作的值。在函数调用时,实参被传递给函数,填充形参,并在函数体内使用。
下面是调用上述函数并传递实参的示例:

result = add_numbers(3, 5)

在这个例子中,3和5是传递给add_numbers函数的实参。函数将使用这些实参来执行计算并返回结果。

以上解释来自chatGpt

显然可能有点啰嗦,喜欢直接一点的同学直接看红框
[图片]

2.2、值传递和引用传递

值传递(pass by value)是指在函数调用时,将实参的值复制一份给形参,函数内部对形参的修改不会影响到原始实参的值。
引用传递(pass by reference)是指在函数调用时,将实参的引用(地址)传递给形参,函数内部对形参的修改会影响到原始实参的值。
简单来说,值传递是对实参进行拷贝,函数内部的操作不会影响到原始实参;而引用传递是对实参的引用进行操作,函数内部的修改会影响到原始实参。

以上解释来自chatGpt

值传递和引用传递的对比如下:
在这里插入图片描述

三、实操

例子一

上个例子:

public static void main(String[] args) throws IOException {int i = 1;change(i);System.out.println(i);
}
public static void change(int a){a = 10;
}

输出:

1

图例:
在这里插入图片描述

由这个例子可见,i 的值还是1,change 方法并没有更改 i 的值,所以是不是可以得出 java 的方法传递是值传递?
那我们开始看下面这个

例子二

public static void main(String[] args) throws IOException {User user = new User();user.setName("yy");change(user);System.out.println(user.getName());
}
public static void change(User a){a.setName("xx");
}

同样是一个change方法,同样是在change方法内修改参数的值,输出:

xx

图例:
暂时无法在飞书文档外展示此内容

经过change方法执行后,实参的值被改变了,那按照上面2.2的引用传递的定义,实际参数的值被改变了,这不就是引用传递了么。那根据上面的两段代码,可以得出新的结论:Java的方法中,在传递普通类型的时候是值传递,在传递对象类型的时候是引用传递,真的是这样吗?其实这个表述还是有误的,不信看下面这个

例子三

public static void main(String[] args) throws IOException {String name = "yy";change(name);System.out.println(name);
}
public static void change(String input){input = "xx";
}

输出结果是:

yy

这个结果好像和上面的 在传递对象类型的时候是引用传递 的结论不符合。同样传递了一个对象,但是对象的原始值却没有改变;name为什么会是这样的呢,我们先来看下图例:
图例:
暂时无法在飞书文档外展示此内容

what?形参input 为啥会是新的内存地址呢?
其实,我们在change(name) 方法中想去修改name 的值,其实阴差阳错的直接修改了input 的应用地址,因为
input = “xx” 的背后是 会 new 一个 string ,把新的引用交给 input,等价于 input = new String(“xx”) 。原来的 “yy” 这个字符串还是由name 持有着,并没有修改到实际参数的值;所以 java 还是值传递,只不过对于对象参数,值是对象的引用地址;

好了,经过上面的概念理解和三个例子,大家应该基本了解了java 的参数传递,那我们把文章开头的例子改一下,输出会是什么样子呢?

public static void main(String[] args) throws IOException {List<String> mockList = Lists.newArrayList("a", "b");System.out.println("1: " + mockList);List<String> result = change(mockList);System.out.println("3: " + mockList);System.out.println("4: " + result);
}public static List<String> change(List<String> input){Collections.sort(input, Comparator.reverseOrder());System.out.println("2: " + input);List<String> result = input;return result;
}

输出:

1: [a, b]
2: [b, a]
3: [b, a]
4: [b, a]

有些同学可能会疑惑,为啥这里 3 输出的又是[b, a]呢,不是说java 是值传递, input 形参的修改不会影响到原来的 mockList 的内容吗?
其实 这里 Collections.sort(input, Comparator.reverseOrder()); 的问题,这个和 input.stream().sorted(Comparator.comparing(String::valueOf).reversed()).collect(Collectors.toList()); 的区别是:

  1. stream() 不会影响到原来集合的内容;Stream API 不会改变数据源,所有操作的最终结果会保存到另外一个对象中。(peek 方法除外,它会修改流中的元素)
  2. sort 却会改变原来内存地址指向的集合内容(本质是对List 内部的数组进行排序);
http://www.lryc.cn/news/64245.html

相关文章:

  • 【面试长文】HashMap的数据结构和底层原理以及在JDK1.6、1.7和JDK8中的演变差异
  • 【25】linux进阶——网络文件系统NFS
  • JAVA入坑之JAVADOC(Java API 文档生成器)与快速生成
  • React | React组件化开发
  • 云计算的优势与未来发展趋势
  • shell编程lesson01
  • 看看人家的MyBatis批量插入数据优化,从120s到2.5s,那叫一个优雅!
  • 软件和信息服务业专题讲座
  • 由 ChatGPT 团队开发,堪称辅助神器!IntelliJ IDEA 神级插件
  • spass modeler
  • kafka的push、pull分别有什么优缺点
  • 【Canvas入门】从零开始在Canvas上绘制简单的动画
  • 【技术整合】各技术解决方案与对应解决的问题
  • 公网远程访问公司内网象过河ERP系统「内网穿透」
  • Win11的两个实用技巧系列之修改c盘大小方法、功能快捷键大全
  • 离散数学下--- 代数系统
  • java基础入门-04
  • 《面试1v1》java反射
  • 【C语言】struct结构体
  • Docker代码环境打包
  • 现代CMake高级教程 - 第 6 章:输出与变量
  • windows/linux文件传输
  • Anoconda安装笔记+win10 更改中文用户名为英文
  • Java Web应用开发 ——作业七
  • echo,date,bc命令详解
  • 【Java笔试强训 29】
  • 如何在微服务下保证事务的一致性
  • 华为OD机试 - 新学校选址(Python)
  • thinkphp6结合layui增删改查综合案列
  • PostgreSQL数据库以任意时间间隔聚合查询group by