`

到底是传值还是传引用?

阅读更多

发现关于java中值传递还是引用传递,一些误解挺多的,我的观点(其实也不是我的观点,咱都是二手贩子)就是java中只有值传递;来吧,咱从头来捋一下,本山大叔在卖拐里不是说了嘛,乱了咱就捋,从头捋一下。

1. 啥叫值传递,啥叫引用传递。

在编译原理中,我们会看到参数的传递有四种,定义如下:

Pass by value: This is the  mechanism supported by C . Value of parameters are copied into called routine.

Pass by reference: No copying is done, but a reference (usually implemented as a pointer) is given to the value. In addition to allowing the called routine to change the

values, it is also efficient means for passing large variables (such as structs).

Pass by value-result: This interesting variant supported by languages such as Ada copies the value of the parameter into the routine, and then copies the (potentially changed)

value back out. This has an effect similar to pass-by-reference, but not exactly.

Pass by name: This rather unusual mechanism acts somewhat like C preprocessor macros and was introduced in Algol. Rather than evaluating the parameter value, the name or expression is actually substituted into the calling sequence and each access to the parameter in the calling body re-evaulates it.

 

由定义可知:并不是我们传递某个参数时,若这个参数是某对象的引用,所以这就是引用传递,引用传递在程序设计领域有其自己的意义。

2. 参数传递是通过值传递,不是通过引用传递。

其实很多书籍都讲到这一点,如practical java 第一条讲的就是它。我们有时候会听到说某方法传递了一个引用,其实应该说准确点,传递的是一个引用(型变量)-pass object reference by value,其传递的内容依然是这个引用型变量的值,即:还是值传递。对象都是通过其对象变量来标识的,而这个对象变量的值并不是对象本身,仅仅是存储在另外一处的该对象的引用。网上很多文章会讲到:这是不对的。

混淆值传递和引用传递通常会有个负面作用:一般认为引用传递的结论还会加上一条-对引用的改变会影响原有变量的值--当然,我们认为这是错误的。

         看下面的代码:

import java.util.ArrayList;
import java.util.List;

public class ByValue {
    public static void main(String args[]) {

        // 1.pass primitive type parameter.
        int i = 0;
        System.out.println("initially the i is " + i);
        byPrimitive(i);
        System.out.println("now the i is " + i);

        // 2. pass reference type parameter and change the parameter's initial value.
        List<String> strList = new ArrayList<String>();
        strList.add("hello world");
        System.out.println("initially the strList is" + strList.toString());
        refType(strList);
        System.out.println("now the strList is" + strList.toString());

        // 3.pass reference type parameter and remain the parameter's initial value .
        List<String> strList2 = new ArrayList<String>();
        strList2.add("hello world ");
        System.out.println("initially the strList2 is" + strList2.toString());
        refType2(strList2);
        System.out.println("now the strList2 is" + strList2.toString());


        List<String> strList3 = new ArrayList<String>();
        strList3.add("hello world 3");
        List<String> strList3Ref = new ArrayList<String>();

        // 4.deep copy
        strList3Ref.addAll(strList3);
        // 5.shallow copy
        strList3.add("hi jude 3");

        System.out.println("now strList3: " + strList3);
        System.out.println("now strList3Ref: " + strList3Ref);
    }

    //1. 修改基本 型变量拷贝的值
    //1.1 在栈内存 的新地址中复制了i的拷贝i',i'的值也是0;
    //1.2 修改了 i'的值为3;
    //1.3 i的值没有 变化
    private static void byPrimitive(int i) {
        i = i + 3;
        System.out.println("the i' is :" + i);
    }

    //2.修改引用 型变量的拷贝的所引用的对象。
    // 2.1 在栈内存 中复制了strList的拷贝 值,新建了引用strList’,strList’的值等同 于strList的值, 即:指向同样的一片堆内存区域;
    // 2.2,对strList'引用的对 象做了修改;2.3因为strList所引用的 对象就是strList'所引用的 对象,所以strList的引用对 象发生了变化。
    private static void refType(List<String> strList) {
        strList.add("hi jude");
        System.out.println("the strList' is :" + strList);
    }

    //3 修改引用 型变量的拷贝的引用。
    //3.1 在栈内存 中复制了strList2的拷贝 值,新建了引用strList2’,strList2'的值等同 于strList2的值, 即:指向同样的一片内存区域;
    //3.2 对strList2'做修改, 即,使其成为局部变量targetList所引用对 象的引用。
    //3.3 修改strList2'所引用对 象的值,即strList2'所引用对 象发生了改变,strList2却没有变 化。
    private static void refType2(List<String> strList) {
        List<String> targetList = new ArrayList<String>();
        strList = targetList;
        strList.add("hi jude");
        System.out.println("the strList' is :" + strList);
    }

}
 

以上代码中的注释已经基本清晰,第三种种"修改引用型变量的拷贝的引用"我个人感觉用途很少,在实际中若是在传递值过程中不想改变原有引用的对象,一般都会
先将该变量所引用的对象内容先拷贝一份,然后再对其操作,这样就不会修改原值。对此,我们会注意到另外一个话题,就
是浅拷贝和深拷贝,在第三点我们再细述。
上面三种情况的内存分配图如下:

1. 修改基本 型变量拷贝的值


 

2.修改引用 型变量的拷贝的所引用的对象。


 

    3. 修改引用 型变量的拷贝的引用。

 

 

 


 

 

3. 浅拷贝 深拷贝 .

    引用到三方方法时得考虑,such as Collection.add() 和collection.addAll(),见代码4和5部分。

 

4. 为啥会有误解?

    4.1 一种:因为java中的对象都是靠对象变量即引用来标识的,所以参数传递中试引用时,当然就是引用传递了。

          解释:如果传递了Object reference那么就是by reference,那么对应的基本类型(primitive type)的参数传递应该就是by primitive ,在这会,reference type 和primitive type是一对对立统一的范畴,在命名上不能顾此失彼吧。归根到底还是对by reference and by value的定义不清楚,参见我们捋的第一条。

    4.2 另外一种:参数传递中,会改变原来的变量的值,所以是引用传递。

          解释:在 所谓的call by reference中,有时候原变量的值,其所引用的对象存在不改变的情况。参见例子.所以不能成为理由。

    4.3 与C++中的by reference混淆。

 

5. 最后,你实在不相信我说的,也该相信Java他爹说的话吧?

Some people will say incorrectly that objects are passed "by reference." In programming language design, the term pass by reference properly means that when an argument is passed to a function, the invoked function gets a reference to the original value, not a copy of its value. If the function modifies its parameter, the value in the calling code will be changed because the argument and parameter use the same slot in memory. If the Java programming language actually had pass-by-reference parameters, there would be a way to declare halve it so that the above code would modify the value of one, or so that common Name could change the variable sirius to null. This is not possible. The Java programming language does not pass objects by reference; it passes object references by value. Because two copies of the same reference refer to the same actual object, changes made through one reference variable are visible through the other. There is exactly one parameter passing mode pass by value and that helps keep things simple.

 

                                                                -----Gosling. The Java Programming Language 第2章 第6节

 

 

 

 

  • 大小: 24.7 KB
  • 大小: 37.3 KB
  • 大小: 40.2 KB
分享到:
评论

相关推荐

    java中传值还是传引用的的认识

    "java中传值还是传引用的认识" Java 中的参数传递是值传递还是引用传递?这是一个经常引发讨论的问题。在 Java 中,参数传递是按值传递的,也就是说,传递给方法的参数是一个副本,而不是原始值本身。 当一个对象...

    Java是传值还是传址引用

    ### Java是传值还是传址引用 #### 一、简单类型是按值传递的 Java在处理简单数据类型(如int、boolean等)时采用的是按值传递的方式。这意味着当你将一个简单类型的值作为参数传递给一个方法时,实际上传递的是这...

    python基础入门教程:传参是传值还是传引用.pdf

    Python中的参数传递并非简单的"传值"或"传引用",而是一种特殊的机制,通常被称为"传对象引用"。这意味着,当你将一个变量作为参数传递给函数时,实际上是传递了这个变量所引用的对象的引用,而不是对象的副本。 ...

    java中传值与传引用

    在Java编程语言中,函数调用时的参数传递方式有两种:传值(Passing by Value)和传引用(Passing by Reference)。虽然Java官方文档中并未明确指出有传引用这一概念,但在实际操作中,Java的行为类似于传引用,尤其...

    java的传值与传引用详解

    在Java中讨论传值还是传引用的问题,其实是源自C语言中的概念。Java中没有指针,因此不能直接谈论传引用的概念。正确的理解应该是:对于简单类型而言,传递的是值的副本;对于对象而言,传递的是指向对象的引用的...

    C++传值调用与引用调用区别实例代码

    当一个函数被调用时,可以通过不同的方式传递参数,其中最常见的是传值(call by value)和传引用(call by reference)两种方法。这两种方式在内存管理、性能影响以及数据修改能力上有着显著的不同。 #### 1. 传值调用...

    23.Java对象作为参数传递是传值还是传引用1

    许多人认为对象是按引用传递,而实际上,Java总是按值传递,包括对象。这里的“值”指的是对象的引用,而不是对象本身。这与C++或C#等其他语言中对象的传递方式有所不同。 首先,我们需要理解Java中的引用概念。当...

    引用类型传值方法

    本篇文章将详细探讨引用类型的传值方式。 首先,理解引用类型的概念至关重要。引用类型包括类(classes)、接口(interfaces)、数组以及委托(delegates),它们在内存中的存储方式与值类型截然不同。对于引用类型...

    JAVA传值与传引用[整理].pdf

    JAVA传值与传引用[整理].pdf

    详解python函数传参是传值还是传引用

    首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题。基本的参数传递机制有两种:值传递和引用...

    php传值和传引用的区别点总结

    在PHP编程中,理解变量的传值和传引用是非常重要的概念,它们决定了函数内部操作对原始变量的影响。下面我们将详细探讨这两个概念的区别、工作原理以及优缺点。 **1. PHP传值** 当一个变量作为参数传递给函数时,...

    vue prop属性传值与传引用示例

    vue组件在prop里根据type决定传值还是传引用。 简要如下: 传值:String、Number、Boolean 传引用:Array、Object 若想将数组或对象类型也以值形式传递怎么办呢?如下方式可以实现: // component-A 引用component-...

    Java中的传值与传引用实现过程解析

    "Java中的传值与传引用实现过程解析" Java中的传值与传引用是Java编程语言中的一种基础概念,它们是Java函数中参数传递的两种方式。 Java中的传值是指函数参数的值被复制到函数内部,在函数内部对参数的修改不会...

    javascript中的变量是传值还是传址的?

    传址和传引用是一回事。 一门编程语言的核心是数据结构,粗略来讲,可以把数据结构分成不可变类型(immutable)和可变类型(mutable)。为什么这么分呢?这涉及到内存分配问题。对于不可变类型,只要分配有限的内存...

    JAVA中传值与引用问题

    在计算机编程领域,特别是对于面向对象语言如Java而言,“传值”与“传引用”的概念是理解数据传递机制的关键所在。Java作为一种广泛使用的高级编程语言,在设计之初就考虑到了如何避免C/C++等语言中的复杂性,特别...

    传值和传引用-综合文档

    在编程世界中,传值和传引用是两个基础但至关重要的概念,它们直接影响着程序的运行方式和数据处理。在LabVIEW(Laboratory Virtual Instrument Engineering Workbench)这种图形化编程语言中,理解这两个概念对于...

    Java到底是传引用还是传值Java开发Java经验技巧共

    Java编程语言在处理参数传递时遵循一种特殊的方式,它既不是纯粹的按值传递,也不是纯粹的按引用传递。理解这一点对于深入学习Java至关重要。在Java中,基本数据类型(如int、float、char等)是按值传递的,而对象则...

    python 函数传参之传值还是传引用的分析

    首先还是应该科普下函数参数传递机制,传值和传引用是什么意思?  函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题。基本的参数传递机制有两种:值传递和引用...

Global site tag (gtag.js) - Google Analytics