一、概念

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

值传递和引用传递,属于函数调用时参数的求值策略(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. 使用FileZilla连接Linux

      FileZilla是一个免费开源的FTP软件,分为客户端版本和服务器版本,具备所有的FTP软件功能.可控性.有条理的界面和管理多站点的简化方式使得Filezilla客户端版成为一个方便高效的FTP ...

  2. java多线程(2) 线程同步

    我们对线程访问同一份资源的多个线程之间,来进行协调的这个东西,就是线程同步.   例子1:模拟了多个线程操作同一份资源,可能带来的问题: package com.cy.thread; public c ...

  3. 任性不用for

    先看最基础的技巧 示例一: function assign(value) { if (value) { return value; } else { return 0; } } console.log ...

  4. .NET单点登录实现方法----两种

    第一种模式:同一顶级域名下cookie共享,代码如下 HttpCookie cookies = new HttpCookie("Token"); cookies.Expires = ...

  5. linux 下java环境的配置

    注意:这里选择下载jdk并自行安装,而不是通过源直接安装(apt-get install) 1.下载jkd( http://www.oracle.com/technetwork/java/javase ...

  6. ALSA声卡16_编写ALSA声卡应用程序_学习笔记

    1.体验 (1)ALSA声卡使用体验:使用arecord录音,使用aplay播放,在Alsa-utils里面) 准备: cd linux-3.4.2 patch -p1 < ../linux-3 ...

  7. Asp.net 的cookie问题

    写代码的发现的小问题 如果写入cookie的时候指定了domin域名 那么删除的时候必须也指定domin域名才行,即使你先读取了这个已经存在的cookie,但是还是要指定domin才能删除 /// & ...

  8. Android:ScrollView和SwipeRefreshLayout高度测量

    今天组里的同事要做一个奇葩的效果,要求在ScrollView里嵌套一个RefreshLayout.类似代码如下: <?xml version="1.0" encoding=& ...

  9. python _/__/__**__区别

    "_"单下划线:"单下划线 " 开始的成员变量叫做保护变量,意思是只有类对象(即类实例)和子类对象自己能访问到这些变量,需通过类提供的接口进行访问:不能用'fr ...

  10. 五、配置jenkins定时构建或上游job触发构建

    我们之前说的都是通过检测github是否有push动作,即代码是否有更新,一旦检测到push动作就出发jenkins构建: 但是除了这种方式,我们可能还会需要定时进行构建,比如在每天的凌晨1:00构建 ...