一、概念

实际上对这两种传递方式,知乎上有个回答说得很好:

值传递和引用传递,属于函数调用时参数的求值策略(Evaluation Strategy),这是对调用函数时,求值传值的方式的描述,而非传递的内容的类型(内容指:是值类型还是引用类型,是值还是指针)。

值类型/引用类型,是用于区分两种内存分配方式,值类型在调用栈上分配,引用类型在堆上分配。

一个描述内存分配方式,一个描述参数求值策略,两者之间无任何依赖或约束关系

实际上意思就是,在函数调用时,不要通过传进去的参数类型去判断是值传递还是引用传递,而是要看这种语言具体的求值策略。

二、详解

在函数调用过程中,调用方提供实参,这些实参可以是常量:

Call(1);             // 常量
Call(x); // 变量
Call(2 * x + 1); // 常量与变量的组合
Call(GetNumber()); // 对其它函数的调用

但是所有这些实参的形式,都统称为表达式(Expression)

求值(Evaluation)即是指对这些表达式的简化并求解其值的过程。

求值策略(值传递和引用传递)的关注的点在于,这些表达式在调用函数的过程中,求值的时机值的形式的选取等问题。求值的时机,可以是在函数调用前,也可以是在函数调用后,由被调用者自己求值。这里所谓调用后求值,可以理解为Lazy Load或On Demand的一种求值方式。

除了值传递和引用传递,还有一些其它的求值策略,详见下表:

求值策略

求值时间

传值方式

值传递(Pass by value)

调用前

值的结果(是原值的副本)

引用传递(Pass by reference)

调用前

原值(原始对象,无副本)

名传递(Pass by name)

调用后(用到才求值)

与值无关的一个名

重点是值传递和引用传递。上面给出的传值方式的表述有些单薄,下表列出了一些二者在行为表象上的区别:

 

值传递

引用传递

根本区别

会创建副本(Copy)

不创建副本

结果

函数中无法改变原始对象

函数中可以改变原始对象

这里的改变不是指mutate, 而是change,指把一个变量指向另一个对象,而不是指仅仅改变属性或是成员什么的,所以说Java是Pass by value,原因是它调用时Copy,实参不能指向另一个对象,而不是因为被传递的东西本质上是个Value。

这些行为,与参数类型是值类型还是引用类型无关。对于值传递,无论是值类型还是引用类型,都会在调用栈上创建一个副本,不同是,对于值类型而言,这个副本就是整个原始值的复制而对于引用类型而言,由于引用类型的实例在堆中,在栈上只有它的一个引用(一般情况下是指针),其副本也只是这个引用的复制,而不是整个原始对象的复制。

综上所述,对于Java的函数调用方式最准确的描述是:参数藉由值传递方式,传递的值是个引用。(句中两个“值”不是一个意思,第一个值是evaluation result,第二个值是value content)。

三、例子

1. 值类型与引用类型

int num = 10;
String str = "hello";

num是基本类型,值就直接保存在变量中。而str是引用类型,变量中保存的只是实际对象的地址。一般称这种变量为"引用",引用指向实际对象,实际对象中保存着内容,比较特别的是,string对象是不可变对象

2. 函数调用

1) 基本类型

void foo(int value) {
value = 100;
}
foo(num); // num 没有被改变

传进foo()里的只是num的一个副本。

2) 没有提供改变自身方法的引用类型

void foo(String text) {
text = "world";
}
str=”hello”
foo(str); // str 也没有被改变

整个过程如下图所示:

3) 提供了改变自身方法的引用类型

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
builder.append("4");
}
foo(sb); // sb指向内容被改变了,变成了"iphone4",但本身还是指向同样的地址。

append前:

append后:

4) 提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
builder = new StringBuilder("ipad");
}
foo(sb); // sb指向内容没有被改变,还是 "iphone"。

赋值前:

赋值后:

四、参考

1. 知乎关于Java 到底是值传递还是引用传递的回答之一

2. 知乎关于Java 到底是值传递还是引用传递的回答之二

(完)

关于java是值传递还是引用传递的更多相关文章

  1. Java中引用类型变量,对象,值类型,值传递,引用传递 区别与定义

    一.Java中什么叫做引用类型变量?引用:就是按内存地址查询       比如:String s = new String();这个其实是在栈内存里分配一块内存空间为s,在堆内存里new了一个Stri ...

  2. java中值传递和引用传递

    最近工作中使用到了值传递和引用传递,但是有点懵,现在看了下面的文章后清晰多了.一下是文章(网摘) 1:按值传递是什么 指的是在方法调用时,传递的参数是按值的拷贝传递.示例如下: public clas ...

  3. Java中的值传递和引用传递

    这几天一直再纠结这个问题,今天看了这篇文章有点思路了,这跟C++里函数参数为引用.指针还是有很大区别. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里 ...

  4. java的值传递和引用传递

    昨天博主在对于值传递和引用传递这里栽了一个大坑啊,导致一下午时间都浪费在这里,我们先说下值传递和引用传递java官方解释: 值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对 ...

  5. java中方法的参数传递机制(值传递还是引用传递)

    看到一个java面试题: 问:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?  答:是值传递.Java 编程语言只有值传递参 ...

  6. java 对象传递 是 值传递 还是 引用传递?

    这个问题说实话我感觉没有太大的意义. 按第一印象和c++的一些思想去理解的话对象传递是引用传递,因为传递过去的对象的值能被改变. 但是又有很多人,不知道从哪里扣出来一句,java中只有值传递,没有引用 ...

  7. java参数传递时到底是值传递还是引用传递

    java参数传递时到底是值传递还是引用传递(baidu搜集) 问”,很多人的BLOG里都引用这些面试题,最近因为工作内容比较枯燥,也来看看这些试题以调节一下口味,其中有一道题让我很费解. 原题是:当一 ...

  8. Java面向对象-方法的值传递和引用传递

    Java面向对象-方法的值传递和引用传递 0 发布时间:『 2016-08-21 14:21』  博客类别:Java核心基础  阅读(197) 评论(0) Java面向对象-方法的值传递和引用传递 方 ...

  9. Does Java pass by reference or pass by value?(Java是值传递还是引用传递) - 总结

    这个话题一直是Java程序员的一个热议话题,争论不断,但是不论是你百度搜也好还是去看官方的文档中所标明的也好,得到的都只有一个结论:Java只有值传递. 在这里就不贴代码细致解释了,让我们来看看一些论 ...

  10. Java值传递和引用传递

    Java总是在讨论是传递还是引用传递,Java没有像C语言那样拥有指针,在看到引用传递和值传递很多的解释之后,更相信引用传递和值传递归根到底都是值传递,只不过引用传递的时候看上去很高大上,其实是把变量 ...

随机推荐

  1. Rabbitmq的调度策略

    Rabbitmq的调度策略是指Exchange在收到消息后依据什么规则把消息投到一个或多个队列中保存.它根两个因素相关:Exchange的类型和Exchange和Queue的绑定关系BindingKe ...

  2. 常用 Git 命令使用教程

    下面整理一下自己在开发过程中经常使用到的 Git 命令.使用 GUI 工具的同学,也可以对照起来看看. Git 配置 1. 在安装完成 Git 后,开始正式使用前,是需要有一些全局设置的,如用户名.邮 ...

  3. 关于ng-class,ng-style的用法

    ng-class的使用几种方式 (1):利用双向数据绑定(className根据chang2的值去匹配类) <div class="{{className}}">... ...

  4. 搭建基于hyperledger fabric的联盟社区(五) --启动Fabric网络

    现在所有的文件都已经准备完毕,我们可以启动fabric网络了. 一.启动orderer节点 在orderer服务器上运行: cd ~/go/src/github.com/hyperledger/fab ...

  5. licode从客户端到连上信令服务器流程

    var config = {audio: true, video: true, data: true, screen: screen, videoSize: [640, 480, 640, 480], ...

  6. Unit03: Spring Web MVC简介 、 基于XML配置的MVC应用 、 基于注解配置的MVC应用

    Unit03: Spring Web MVC简介 . 基于XML配置的MVC应用 . 基于注解配置的MVC应用 springmvc (1)springmvc是什么? 是一个mvc框架,用来简化基于mv ...

  7. c#实现QQ群成员列表导出及邮件群发之群列表及群成员获取

    主题已迁移至:http://atiblogs.com/ ITO-神奇的程序员

  8. ios真机连接不上记录,再次执行脚本说找不到真机的解决

    1.连接其他手机iphone 6 plus   和  iphone x 的时候,连接不上 appium desired capabilities 获取不了元素 提示 An unknown server ...

  9. Codeforces-708C(树形DP)

    一.题意 给定一颗树,对于每一个节点,判断能否在树中删除某一条边,然后在任意两个节点之间加一条边,使这个点成为重心. 注:删除树中某一条边后,标程并不会这么无聊地把这棵树变成两个孤立的连通图,而是再让 ...

  10. 利用JAVA操作Redis---demo

    package com.js.ai.modules.pointwall.interfac; import java.util.HashMap; import java.util.Iterator; i ...