文档章节

如何理解Java的值传递

o
 osc_zoa3moe9
发布于 2019/12/07 15:14
字数 1100
阅读 15
收藏 0

精选30+云产品,助力企业轻松上云!>>>

结论

为了加深印象,先把结论放在文章开头。 ++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 只存在按值传递。

o
粉丝 1
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
程序员必须知道的JVM堆和JVM栈深入学习(干货速取!!!)

感觉还是挺好的,分享一下哈,自取噢! JVM栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;JVM堆解决的是数据存储的问题,即数据怎么放、放在哪儿,另外JVM堆中存的是对象。JVM栈中...

煌sir
05/01
29
0
JVM基础:深入学习JVM堆与JVM栈

以前堆是干啥栈是干啥都知道,就是没连在一起想想。感觉讲的不错的一篇儿~~JVM栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;JVM堆解决的是数据存储的问题,即数据怎么放、放在...

李星
2014/06/04
732
1
【转】Java百问

程序员经常可以通过搜索或者记忆来完成代码,但是许多时候并不真正理解为什么那样写。也就是说,有一定经验的程序员不会犯一些低级的语法错误,但是因为不深入理解有可能造成一些高级错误,比...

一只死笨死笨的猪
2014/09/30
18
0
我要彻底给你讲清楚,Java就是值传递,不接受争辩的那种!

前言 关于Java中方法间的参数传递到底是怎样的、为什么很多人说Java只有值传递等问题,一直困惑着很多人,甚至我在面试的时候问过很多有丰富经验的开发者,他们也很难解释的很清楚。 我很久也...

wx5e957713e71c9
04/14
0
0
java中的参数传递——值传递、引用传递

参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递。 在 Java 应用程序中永远不会传递对象,而只传递对象引用。 因此是按引用传递对象。 Java 应用程序...

yeahlife
2018/07/21
10
0

没有更多内容

加载失败,请刷新页面

加载更多

Mysql 通过binlog日志恢复数据

Binlog日志,即binary log,是二进制日志文件,有两个作用,一个是增量备份,另一个是主从复制,即主节点维护一个binlog日志文件,从节点从binlog中同步数据,也可以通过binlog日志来恢复数据...

osc_lduvstkg
34分钟前
4
0
前端js日期时间格式转换

前端前后端接口处理时经常会遇到需要转换不同时间格式的情况,比如时间戳格式转换成正常日期显示来进行前端展示。 下面是分享一些不同格式的日期转换函数方法。 /** * 时间戳转时间 * @param...

osc_gccs85s0
36分钟前
9
0
微服务中如何设计一个权限授权服务

基于角色的访问控制 (RBAC)   是将系统访问限制为授权用户的一种方法,是围绕角色和特权定义的与策略无关的访问控制机制,RBAC的组件使执行用户分配变得很简单。   在组织内部,将为各种...

osc_ie20bwji
38分钟前
12
0
前端js日期时间格式转换

前端前后端接口处理时经常会遇到需要转换不同时间格式的情况,比如时间戳格式转换成正常日期显示来进行前端展示。 下面是分享一些不同格式的日期转换函数方法。 /** * 时间戳转时间 * @param...

osc_sqfqhs81
39分钟前
38
0
(转)【D3D11游戏编程】学习笔记三:XNAMath之XMMATRIX

(注:【D3D11游戏编程】学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~) 在熟悉了XMVECTOR的风格及规则之后,再来了XNA数学库中的矩阵就容易...

osc_yumj26qz
41分钟前
32
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部