如何理解Java的值传递
结论
为了加深印象,先把结论放在文章开头。
++Java中只有值传递++。
形参与实参
在理解Java的值传递
实参Argument
实际参数,主调用函数传递给调用函数的参数
形参Parameter
形式参数,并非实际存在的变量,只在函数定义的函数内部使用。在调用函数时,实参将会给形参赋值,从而实现主调函数向调用函数传输数据的目的。
所谓的传递,就是实参给形参赋值的过程。这是我们理解值传递和引用传递的基础。
基本类型与引用类型
基本类型的变量保存值,即值就是变量自身。
而引用类型的变量的值表示对象的引用地址,而非对象自身。
Java内存空间分为 heap 和 stack。对于基本类型的局部变量而言,空间直接在 stack 中分配(例如int a
,虚拟机会为a
在 stack 中分配一个四字节的内存空间,用来存放a
的值),而对于引用类型的局部变量而言,虚拟机会现在 stack 中分配一个四字节的空间,用来存放指向 heap 的地址,同时在 heap中分配一块地址用来存放对象。
按值传递和引用传递
按值传递
所谓值传递,就是在实参为形参赋值的时候,将值赋给形参。
而引用传递,是是在实参为形参赋值的时候,直接将引用(即地址)赋给形参。
所谓的 Java 按值传递,就是说明实参为形参赋值时,只存在值副本的拷贝。
测试代码
一个简单的测试代码:
public class ValOrRef {
public static void main(String[] args){
System.out.println("SCENE 1:--------------------");
scene1();
System.out.println("SCENE 2:--------------------");
scene2();
System.out.println("SCENE 3:--------------------");
scene3();
}
protected static void scene1(){
int argument = 1;
incrVal(argument);
System.out.println("After method invoke, argument: " + argument);
}
protected static void scene2(){
Foo argument = new Foo("original");
changeStr(argument);
System.out.println("After method invoke, argument: " + argument);
}
protected static void scene3(){
Foo argument = new Foo("original");
createNewInstance(argument);
System.out.println("After method invoke, argument: " + argument);
}
private static void incrVal(int parameter){
parameter = parameter + 1;
System.out.println("parameter: " + parameter);
}
private static void changeStr(Foo parameter){
parameter.setStr("changed");
System.out.println("parameter: " + parameter);
}
private static void createNewInstance(Foo parameter){
parameter = new Foo("Brand New");
System.out.println("parameter: " + parameter);
}
static class Foo{
private String str;
public Foo(String str){
this.str = str;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Foo{" +
"str='" + str + '\'' +
'}';
}
}
}
先看输出的测试结果:
SCENE 1:--------------------
parameter: 2
After method invoke, argument: 1
SCENE 2:--------------------
parameter: Foo{str='changed'}
After method invoke, argument: Foo{str='changed'}
SCENE 3:--------------------
parameter: Foo{str='Brand New'}
After method invoke, argument: Foo{str='original'}
Scene1分析
对于Scene1而言,首先主调函数scene1()
方法在 自己的函数调用栈上分配了一个四字节的空间,用来存放 argument
的值(值为1)。然后在调用incrVal(int val)
时,会在incrVal()
自己的函数调用栈上,为parameter
同样分配一个四字节的空间,同时拷贝一份argument
的值(值为1)赋给parameter
。
此时argument
和parameter
除了值相等之外,没有任何联系。因此在incrVal()
内部修改了parameter
的值对argument
没有任何影响。
Scene2分析
同样对于Scene2而言,主调函数在自己的函数调用栈上分配了一个四字节空间,用来存放argument
的引用,其值是指向 heap 的一个地址,虚拟机可以通过地址值从 heap 中找到指定的对象。主调函数在调用changeStr()
时,虚拟机为changeStr()
同样分配了四字节空间存放paramter
的值,并将argument
的值(指向 heap的地址)赋值给parameter
。
和Scene1相同,argument 和 parameter 除了值相等外,没有其他关联。
当changeStr()
内部调用paramter.setStr()
时,虚拟机会根据paramter
的值找到 heap 上对应的Foo
对象,然后修改了Foo
对象上str
所指的值。
由于paramter
和argument
的值指向了相同的对象,因此argument
的对象也发生了改变。
但赋值的过程依旧是按值传递。
Scene3分析
对于Scene3,argument
保存在主调函数的函数调用栈上,然后在调用createNewInstance
时,把值(表示 heap 上的某个空间地址)赋值给了parameter
。而在函数内部,parameter
的值又被修改成了新创建对象的地址。但是外部argument
的值仍然是指向之前的对象。因此argument
并未发生改变。
总结
最后在总结一次,Java 只存在按值传递。
如何理解Java的值传递的更多相关文章
- 堆栈详解 + 彻底理解Java的值传递和引用传递
本文旨在用最通俗的语言讲述最枯燥的基本知识 学过Java基础的人都知道:值传递和引用传递是初次接触Java时的一个难点,有时候记得了语法却记不得怎么实际运用,有时候会的了运用却解释不出原理,而且坊间讨 ...
- java面试3-对于java中值传递的理解(Hollis)
这是根据Hollis的直面java内容习得(有兴趣的可以加他微信公众号) 对于初学者来说,要理解java中的值传递很难理解,为什么说java只有值传递?那引用传递呢? java中的错误理解: 错误理解 ...
- java是值传递还是引用传递
首先写一个简便的Employee,以便测试使用. class Employee { private String name; public Employee(String name) { this.n ...
- Java中值传递和引用传递的概念
很多书中都提到了在Java中只存在值传递,但是今天在一个NanoHTTPD的源码中看到这样一段: if (qmi >= 0) { decodeParms(uri.substring(qmi + ...
- Does Java pass by reference or pass by value?(Java是值传递还是引用传递) - 总结
这个话题一直是Java程序员的一个热议话题,争论不断,但是不论是你百度搜也好还是去看官方的文档中所标明的也好,得到的都只有一个结论:Java只有值传递. 在这里就不贴代码细致解释了,让我们来看看一些论 ...
- Java是值传递还是引用传递?
Java的值传递和引用传递在面试中一般都会都被涉及到,今天我们就来聊聊这个问题.这个问题一般是相对函数而言的,也就是Java中所说的方法参数,那么我们先来回顾一下在程序设计语言中有关参数传递给方法的两 ...
- Java的值传递和引用传递的说法
学过Java基础的人都知道:值传递和引用传递是初次接触Java时的一个难点,有时候记得了语法却记不得怎么实际运用,有时候会的了运用却解释不出原理,而且坊间讨论的话题又是充满争议:有的论坛帖子说Java ...
- 数据存储在哪里? Java是值传递还是引用传递?
寄存器 : 最快的存储区,位于处理器中,寄存器会按需求自行分配空间,java不能控制寄存器,所以在程序中感觉不到它的存在 栈(stack) : 位于RAM(内存)中,速度仅次于寄存器,存储对象的引用( ...
- Java 为值传递而不是引用传递
——reference Java is Pass by Value and Not Pass by Reference 其实这个问题是一个非常初级的问题,相关的概念初学者早已掌握,但是时间长了还是容易 ...
随机推荐
- 怎么用scratch做大鱼吃小鱼
行走代码不说了.出鱼代码大概就是 棋子被点击时 重复执行 移到x:从()到()任意选一个数,y一样 克隆自己 等待你想要的秒数.吃鱼代码就是 当作为克隆体启动是 重复执行 如果碰到()那么 删除克隆体 ...
- readthedocs网托管持多语言文档
希望在readthedocs上创建支持多语言的文档,效果类似: 通过语言选项,可以切到到不同的语言版本:实现这个目标包含两个主要步骤: 在本地对文档进行翻译 在readthedocs.org上配置翻译 ...
- javascript入门 之 zTree(十四 增删查改)(一)
<!DOCTYPE html> <HTML> <HEAD> <TITLE> ZTREE DEMO - beforeEditName / beforeRe ...
- 如何在云开发静态托管中使用Jekyll
如何在云开发静态托管中使用Jekyll 介绍 Jekyll 是一个简单的博客形态的静态站点生产机器,通过它,我们可以搭建一个完整的可发布的静态博客网站. Jekyll 也可以运行在 GitHub Pa ...
- matplotlib IdentityTransform(原地变换)
2020-04-12 23:33:56 -- Edit by yangrayIdentityTransform继承于Affine2DBase类,它是一个高效实现原地变换的类.(不知道有什么用,变换前后 ...
- 拓扑排序入门详解&&Educational Codeforces Round 72 (Rated for Div. 2)-----D
https://codeforces.com/contest/1217 D:给定一个有向图,给图染色,使图中的环不只由一种颜色构成,输出每一条边的颜色 不成环的边全部用1染色 ps:最后输出需要注意, ...
- mount --bind绑定命令
将目录或文件DirFile-1绑定到目录或文件DirFile-2上,所有对DirFile-2的访问就是对DirFile-1的访问 mount --bind [DirFile-1] [DirFile-2 ...
- 一个hql 关键字member(非mysql)引起的 vo 数据 保存数据库错误
2015-03-19 14:16:29,285 ERROR [Thread-3] (DAOHelper.java:312) - updateByEntityPK:com.agileeagle.dao. ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十二)之Error Handling with Exceptions
The ideal time to catch an error is at compile time, before you even try to run the program. However ...
- 收集免费的接口服务,做一个api的搬运工
hello, 大家好,今天给大家推荐的开源项目在某种程度上极大的方便了广大的开发者,这个开源项目统计了网上诸多的免费API,为广大开发者收集免费的接口服务,专心致志做一个API的搬运工,每月定时更新新 ...