Java是值传递还是引用传递?与求值策略之间有什么关系

Java是值传递还是引用传递?与求值策略之间有什么关系

  1. 对于Java中方法之间的参数传递到底是什么样的?
  2. 为什么很多人说Java只有值传递?很多程序员对于这个问题的理解都不一样,甚至很多人理解的是错误的。
  3. 还有的人可能知道Java中的参数传递是值传递,但是说不出来为什么。这个问题 一直困惑着很多人。有时候在面试的时候面试官也会问到这个问题。
  4. 一直有一种很混沌的感觉,近期查看了许多博客、技术文档,将最终的结论记录在这篇博客中。

对于这个问题的误区

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

先复习一下什么是形参、什么是实参

  • 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。

  • 形式参数是指在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。形参就是函数自己的变量,其初始值来源于函数的调用。只有在程序执行过程中调用了函数,形参才有可能得到具体的值。

  • 在调用函数时,实参将赋值给形参。因而,必须注意实参的个数,类型应与形参一一对应,并且必须要有确定的值。

  • 图1:举例
    形参?实参?

求职策略?

求值策略(Evaluation strategies)是确定编程语言中表达式求值的一组(通常确定性的)规则。求值策略定义何时和以何种顺序求值给函数的实际参数、什么时候把它们代换入函数、和代换以何种形式发生。
进行方法调用的时候,需要把实际参数传递给形式参数,那么传递的过程中到底传递的是什么东西?这个就涉及到求值策略的概念

求值策略分为两大基本类,基于如何处理给函数的实际参数,分位严格的和非严格的。大多数编程语言对函数都使用严格求值。在“严格求值”中,函数调用过程中,主函数的实际参数总是在被调用函数调用之前求值
重点了解一下,在严格求值中 ==传值调用(Call by value)、传引用调用(Call by reference)以及传共享对象调用(Call by sharing)==几个关键的求值策略。

  • 传值调用(值传递)
    在传值调用中,实际参数先被求值,然后其值通过 复制 ,被传递给被调函数的形式参数。因为形式参数拿到的只是一个"拷贝",所以如果在被调函数中改变了形式参数的值,并不会改变实际参数的值。

  • 传引用调用(应用传递)
    在传引用调用中,传递给函数的是它的实际参数的隐式引用而不是实参的拷贝。因为传递的是引用,所以,如果在被调函数中改变了形式参数的值,改变对于调用者来说是可见的。

  • 传共享对象调用(共享对象传递)
    传共享对象调用中,先获取到实际参数的地址,然后将其复制,并把该地址的拷贝传递给被调函数的形式参数。因为参数的地址都指向同一个对象,所以我们称也之为"传共享对象",所以,如果在被调函数中改变了形式参数的值,调用者是可以看到这种变化的。

  • 其实传共享对象调用和传值调用的过程几乎是一样的,都是进行"求值"、“拷贝”、“传递”。但是,传共享对象调用和内传引用调用的结果又是一样的,都是在被调函数中如果改变参数的内容,那么这种改变也会对调用者有影响。因为传共享对象调用的过程和传值调用的过程是一样的,而且都有一步关键的操作,那就是"复制",所以,可以认为传共享对象调用是传值调用的特殊的形式。

  • 列表显示,直观的表达:

值传递引用传递共享对象传递
区别创建副本(copy)不创建副本(no-copy)创建副本(no-copy)
所以无法改变原先对象可以改变对象可以改变对象
  • Java中使用到的是哪种求值策略哪?
    其实在 《The Java™ Tutorials》中,是有关于这部分内容的说明的。首先是关于基本类型描述如下:
/**
Primitive arguments, such as an int or a double, are passed into methods by value. 
This means that any changes to the values of the parameters exist only within the scope of the method. 
When the method returns, the parameters are gone and any changes to them are lost
*/

即,原始参数通过值传递给方法。这意味着对参数值的任何更改都只存在于方法的范围内。
当方法返回时,参数将消失,对它们的任何更改都将丢失。

关于对象传递的描述如下:

/**
Reference data type parameters, such as objects, are also passed into methods by value. 
This means that when the method returns, the passed-in reference still references the same object as before. However, 
the values of the object’s fields can be changed in the method, if they have the proper access level.
*/

就是说,引用数据类型参数(如对象)也按值传递给方法。这意味着,当方法返回时,
传入的引用仍然引用与以前相同的对象。但是,如果对象字段具有适当的访问级别,
则可以在方法中更改这些字段的值
这一点官方文档已经很明确的指出了,Java就是值传递,只不过是把对象的引用当做值传递给方法。这不就是共享对象传递么
**&&

值传递 和 引用传递

主要区别是否会进行复制
在这里插入图片描述

值传递和共享对象传递

既然共享对象传递是值传递的一个特例,那么为什么他们的现象是完全不同的呢?(1. 值传递,对于主方法来说是不会感应到是否发生变化的。2. 共享对象传递主方法是可以感应到是否发生变化的。)

  • Java对象的传递,是通过复制的方式把引用关系传递了,如果我们没有改引用关系,而是找到引用的地址,把里面的内容改了,是会对调用方有影响的,因为大家指向的是同一个共享对象。
  • 如果是修改了引用。是不会对原来的对象有任何影响的,但是如果直接修改共享对象的属性的值,是会对原来的对象有影响的。

在这里插入图片描述

在这里插入图片描述

总结

  • 值传递和引用传递最大的区别是传递的过程中有没有复制出一个副本来,如果是传递副本,那就是值传递,否则就是引用传递。

  • 在Java中,其实是通过值传递实现的参数传递,只不过对于Java对象的传递,传递的内容是对象的引用。可以总结说,Java中的求值策略是共享对象传递,这是完全正确的。

  • 但是,简单点直接说Java中只有值传递,只不过传递的内容是对象的引用。这也是没问题的。

  • 但是,绝对不能认为Java中有引用传递。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值