ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

关于Java中的值传递问题的一些思考

2022-07-27 15:05:10  阅读:143  来源: 互联网

标签:调用 Java 传递 参数 引用 思考 求值


Java中方法之间的参数传递问题,一直是我之前比较疑惑的地方。有人说Java中只有值传递,没有引用传递;也有人说Java中参数传递如果是普通类型,那么就是值传递,如果是对象,那么就是引用传递。很多人对这个问题的理解不尽相同。下面我们就针对上面的一些观点,深入的讲解一下。

参考资料:《深入理解Java核心技术》

如果你也有如下几个观点,那么一定要好好看接下来的类容:

  • 错误观点一: 值传递和引用传递,区分的条件是传递的内容,如果是值 ,那么就是值传递;如果是引用那么就是引用传递
  • 错误观点二:Java是引用传递
  • 错误观点三:传递的参数如果是普通类型, 那么就是值传递;如果是对象类型,那么就是引用传递。

上结论:

Java 中方法参数传递方式是按值传递

  • 如果参数是基本类型, 传递的是基本类型的字面量值的拷贝(传值调用)
  • 如果传递的参数是引用类型,传递的是该参数所引用的对象在堆内存中的地址的拷贝。(传共享对象调用)

1、基础概念

针对上述问题的提出,我们先来了解一些必要,且很基础的问题。

1.1、实参和形参

结论:实际参数是调用有参方法时真正传递的内容,而形式参数是用于接收实参内容的参数。

​ 我们都知道,在Java中定义方法时是可以定义参数的。比如 Java 中的 main 方法,public static void main(String[] arsg) , 其中args 就是参数。 参数在程序语言中分为形式参数和实际参数。

  • 形式参数:在定义函数名和函数体时使用的参数,目的是接收函数调用者调用函数时所传递的参数。
  • 实际参数:在调用有参函数时,主调用函数和被调用函数之间有数据传递关系,在主调用函数调用一个函数时,函数名后年括号内的参数被称为实际参数。

1.2、求值策略

当调用方法时,需要把实际参数传递给形式参数, 在传递的过程中到底传递的是什么?

这其实就是程序设计中 求值策略的概念。

​ 按照如何处理传递给函数的实际参数, 求职策略分为:严格求值非严格求值

1.2.1、严格求值

在函数调用过程中,传递给函数的实际参数总是在应用这个函数之前进行求值。

多数现存编程语言对函数都是使用严格求值策略。

在严格求值中,有几个比较关键的求值策略是我们比较关系的:

  • 传值调用(call by value) -- 值传递
    • 传值调用其实就是我们所谓的值传递,在传值调用的过程中,实际参数先背求值,然后其值通过复制,被传递给被调用函数的形式参数。
    • 因此形式参数获取的只是一个“局部拷贝”,所以如果再被调用函数中改变形式参数的值, 则并不会改变实际参数的值。
  • 传引用调用(call by refrence) -- 引用传递
    • 在传引用调用中,吗传递给函数的是他的实际参数的隐式引用而不是实际参数的副本。因为传递的是引用,所以如何在被调用函数中改变形式参数的值, 改变对调用者来说是可见的。
  • 传共享对象调用(call by sharing) -- 共享对象传递
    • 传递共享对象调用中,先获取实际参数的地址,然后将其复制,并把该地址的副本传递给被调用函数的形式参数。因为参数的地址都指向同一个对象,所以也被称为“传共享对象”,如果再被调用函数中改变形式参数的值,调用者是可以看到这种变化的。

其实我们会发现, 传值引用和传共享对象引用的调用过程几乎是一样的,都是进行 求值 -- 复制 -- 传递。但是他们的结果又是不一样的,这是为什么呢?对于这个问题,我们更多的应该关注的是过程, 而不是结果。

  • 因为传共享对象调用的过程和传值调用的过程是一样的,而且都有进一步关键的操作 就是复制,所以通常我们认为 传共享对象引用就是传值引用的一个特例。 (值 -> 共享对象的地址)

  • 传值调用是值在调用过程中将实际参数复制一份并传递到函数中, 传引用调用是值在调用过程中将实际参数的引用直接传递到函数中。

  • 所以传值调用和传引用的调用的主要区别就是 实际参数是直接传递的, 还是传递副本的。

2、Java中的对象传递

我们前面讲过,无论是值传递还是引用传递, 其实都是系统设计中的求值策略的一种。

在 《The Java Tutorials》 中, 有关这部分的内容, 也做了说明。

关于基本类型的描述 ,大致的意思是:

​ 原始参数通过值传递给方法。这就意味着对参数值的任何改变都只存在于方法的范围内。当方法返回时,参数将消失,对它的任何改变都将丢失。

关于对象的描述,大致意思是:

​ 引用数据类型参数(对象)也是按照值传递给方法, 这意味着, 当方法返回时,传入的引用仍然引用与以前相同的对象。但是,如果对象字段具有适当的访问级别, 则可以在方法中更改这些字段的值。

​ 上面的引言是官方指南的说明,Java就是值传递,只不过是把对象的引用(地址)当做值传递给方法。这就是我们前面所说的 传共享对象调用。

​ 其实Java中使用的求值策略就是传共享对象调用,也就是说,Java会将对象的地址的副本传递给被调用函数的形式参数。只不过“传共享对象调用” 这个词并不常用,所以Java 社区的人通常说这是 传值调用。这么说也没错, 因为传共享对象调用其实也就是传值调用的一个特例而已。

3、值传递和共享对象传递的现象冲突是否冲突

3.1、示例代码

public class User {

    private String name;
    private String male;

    public User() {
    }

    public User(String name, String male) {
        this.name = name;
        this.male = male;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMale() {
        return male;
    }

    public void setMale(String male) {
        this.male = male;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", male='" + male + '\'' +
                '}';
    }
}

public class PassTest {
    public static void main(String[] args) {
        PassTest passTest = new PassTest();
        User qzk = new User();
        qzk.setName("qzk");
        qzk.setMale("男");
        passTest.pass(qzk);
        System.out.println("print in main ,  user : "+qzk);
    }


    public  void pass(User user){
        user.setName("qian zheng kai");
        System.out.println("print in pass ,  user : " + user);
    }
}

3.2、图解分析

image-20220727144052414

​ 在参数传递的过程中,实际参数的地址 0x123456 被赋值给了形参。 这个过程其实就是值传递,只不过传递的值的内容是对象的引用。

也就是说,Java对象的传递是通过复制的方式吧引用传递了,如果我们没有修改引用关系,而是找到引用的地址, 把里面的内容修改了,则会对调用方有影响,因为形参和实参指向的是同一个共享对象。

小结:

  • Java 中的求值策略是共享对象传递
  • 或者说 Java中只有值传递, 只不过传递的内容是对象的引用。

标签:调用,Java,传递,参数,引用,思考,求值
来源: https://www.cnblogs.com/qianzhengkai/p/16524831.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有