结论

为了加深印象,先把结论放在文章开头。

++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

此时argumentparameter除了值相等之外,没有任何联系。因此在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所指的值。

由于paramterargument的值指向了相同的对象,因此argument的对象也发生了改变。

但赋值的过程依旧是按值传递。

Scene3分析

对于Scene3,argument保存在主调函数的函数调用栈上,然后在调用createNewInstance时,把值(表示 heap 上的某个空间地址)赋值给了parameter。而在函数内部,parameter的值又被修改成了新创建对象的地址。但是外部argument的值仍然是指向之前的对象。因此argument并未发生改变。

总结

最后在总结一次,Java 只存在按值传递。

如何理解Java的值传递的更多相关文章

  1. 堆栈详解 + 彻底理解Java的值传递和引用传递

    本文旨在用最通俗的语言讲述最枯燥的基本知识 学过Java基础的人都知道:值传递和引用传递是初次接触Java时的一个难点,有时候记得了语法却记不得怎么实际运用,有时候会的了运用却解释不出原理,而且坊间讨 ...

  2. java面试3-对于java中值传递的理解(Hollis)

    这是根据Hollis的直面java内容习得(有兴趣的可以加他微信公众号) 对于初学者来说,要理解java中的值传递很难理解,为什么说java只有值传递?那引用传递呢? java中的错误理解: 错误理解 ...

  3. java是值传递还是引用传递

    首先写一个简便的Employee,以便测试使用. class Employee { private String name; public Employee(String name) { this.n ...

  4. Java中值传递和引用传递的概念

    很多书中都提到了在Java中只存在值传递,但是今天在一个NanoHTTPD的源码中看到这样一段: if (qmi >= 0) { decodeParms(uri.substring(qmi + ...

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

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

  6. Java是值传递还是引用传递?

    Java的值传递和引用传递在面试中一般都会都被涉及到,今天我们就来聊聊这个问题.这个问题一般是相对函数而言的,也就是Java中所说的方法参数,那么我们先来回顾一下在程序设计语言中有关参数传递给方法的两 ...

  7. Java的值传递和引用传递的说法

    学过Java基础的人都知道:值传递和引用传递是初次接触Java时的一个难点,有时候记得了语法却记不得怎么实际运用,有时候会的了运用却解释不出原理,而且坊间讨论的话题又是充满争议:有的论坛帖子说Java ...

  8. 数据存储在哪里? Java是值传递还是引用传递?

    寄存器 : 最快的存储区,位于处理器中,寄存器会按需求自行分配空间,java不能控制寄存器,所以在程序中感觉不到它的存在 栈(stack) : 位于RAM(内存)中,速度仅次于寄存器,存储对象的引用( ...

  9. Java 为值传递而不是引用传递

    ——reference Java is Pass by Value and Not Pass by Reference 其实这个问题是一个非常初级的问题,相关的概念初学者早已掌握,但是时间长了还是容易 ...

随机推荐

  1. 1065 A+B and C (64bit) (20分)(水)

    Given three integers A, B and C in [−], you are supposed to tell whether A+B>C. Input Specificati ...

  2. Redis设计与实现笔记 - hash

    基本结构如下 初始状态一直使用 dictht[0],即 0 号哈希表 在发生扩容 rehash的时候,开始渐进式向 dictht[1]哈希表转移, 转移完成后交换 dicth[0] 与 dictht[ ...

  3. 从一个慢查询到MySQL字符集编码

    从一个慢查询到MySQL字符集编码 目录 从一个慢查询到MySQL字符集编码 1. 问题起源 2. MySQL字符集和字符集排序规则 2.1 字符集相关概念 2.2 MySQL中的字符集和字符集排序规 ...

  4. mpvue-新建页面、页面跳转、自适应单位

    1.mpvue怎么新建页面? (1)粘贴复制一个页面文件夹,只需要改文件夹名- 文件名不需要改,main.js里的东西不用动.export default里更改局部顶部栏配置. (2)index.vu ...

  5. Git常用命令(二)

    git clone + URL 获取该项目源代码 $ git log 回顾提交历史 $ git log -p -(数字) 用来显示每次提交的内容差异+(数字)表示看最近几条 $ git log --s ...

  6. 【Web】阿里icon图标webpack插件(webpack-qc-iconfont-plugin)详解

    webpack-qc-iconfont-plugin webpack-qc-iconfont-plugin是一个webpack插件,可以轻松地帮你将阿里icon的图标项目下载至本地 开发初衷 之前已经 ...

  7. linux被当矿机排查案例

    1.发现服务器变的特别卡,正常服务运行很慢. 到服务器上查询一番发现top下发现     bashd的进程占用100%CPU了. find /-name bashd* //第一次查询文件占用目录kil ...

  8. Dos 命令启动网卡

    禁用网卡: netsh interface set interface "本地连接" disabled 启用网卡 : netsh interface set interface & ...

  9. Python—一个简单搜索引擎索引库

    因为课业要求,搭建一个简单的搜索引擎,找了一些相关资料并进行了部分优化(坑有点多) 一.数据 数据是网络上爬取的旅游相关的攻略页面 这个是travels表,在索引中主要用到id和url两个字段. 页面 ...

  10. 复习python的__call__ __str__ __repr__ __getattr__函数 整理

    class Www: def __init__(self,name): self.name=name def __str__(self): return '名称 %s'%self.name #__re ...