`

java经典问题:传值还是传引用(转过来的)

阅读更多
经典的问题,但却不容易弄懂,尤其对有c基础的java程序员来说,更容易引起混乱,这里我试图简单点描述。

“java函数是传值的,java函数传递的参数是对象的引用”

这两句话好像初听上去有些矛盾,但却是事实,因而引起很多初学者的混乱。在这里我试图据个简单的例子来说明java的这个特性,可能不全面,希望大家来补全。


public class TestRef {

public static void main(String[] args)
{
ValueObject vo1 = new ValueObject("A", 1);
System.out.println("after vo1: " + vo1.getName()); //=A

changeValue1(vo1);
System.out.println("after changeValue1: " + vo1.getName());
                //=A1, changed

changeValue2(vo1);
System.out.println("after changeValue2: " + vo1.getName());
                //=A1, changeValue2内部的赋值不会影响这里。
}

/**
* 使用vo1自身的函数对其内部数据进行改变是有效的,函数外可反映出来
* 这种object称为可变的(mutable)
* @param vo1
*/
private static void changeValue1(ValueObject vo1) {
vo1.setName("A1");
}

/**
* 在函数内给vo1重新赋值不会改变函数外的原始值
* @param vo1
*/
private static void changeValue2(ValueObject vo1) {
vo1 = new ValueObject("B", 2);
System.out.println("inside changeValue2: "+ vo1.getName());
                //=B,赋值操作引起的结果变化仅在changeValue2内部有效
}
}

class ValueObject {

public ValueObject() {}

public ValueObject(String name, int id)
{
this.name = name;
this.id = id;
}

private String name;
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}



解释,vo1作为一个object,当它被用作函数参数的时候传递给函数的是一个引用值,这个名称有点怪,又有引用又有值,到底是引用还是值呢,就看你怎么理解了。如果你是去考试,官方的答案是值。可是看起来又象引用啊,希望从这个例子,你能理解java参数传递和和C/C++程序中的引用传递的不同的地方。另外,这也是java作为OO语言的特性之一:封装的体现。

先讲一下对象赋值的关系,举例来说,下列代码:

ValueObject v2, v3;
v2 = new ValueObject("C", 3); 粗体的部分创建了一个数据结构,假设存放在内存地址A000,赋值给句柄 v2
v3 = new ValueObject("D", 4); 粗体的部分创建了一个数据结构,假设存放在内存地址B000,赋值给句柄 v3
v2 = v3; 这句话的作用是把操作B000的地址的句柄的值付给了v2的句柄,使得v2和v3一样操作B000的地址,这意味着:
1.原来v2指向的地址A000变成无主的内存地址,将自动被jvm回收。
2.既然v2和v3指向同一片地址,对v3的修改v2也能得到,反之亦然。

整理得下列代码,请感兴趣的朋友运行验证
ValueObject v2 = new ValueObject("C", 3);
ValueObject v3 = new ValueObject("D", 4);
v2 = v3;
System.out.println("after v2=v3");
System.out.println("v2= "+ v2.getName());//=D
System.out.println("v3= "+ v3.getName());//=D
v3.setName("C1");
System.out.println("after v3 setnameTo C1");
System.out.println("vo2= "+ v2.getName());//=C1
System.out.println("vo3= "+ v3.getName());//=C1

因此,可以得出结论,java中对象的每个实例(instance, 比如vo1, v2, v3 都是ValueObject的实例)的内存地址是唯一的,它一旦被创建,能够对这个地址进行操作的就是每个实例自己,如果ValueObject类中没有public void setName之类的方法对这个类的实例中的数据进行修改的话,程序是没有任何别的方法可以修改ValueObject类的实例中的数据,这个就是java的封装特性。对于不提供修改内部数据的方法的类,我们称为不可变(immutable)的类。在函数中对传入的参数变量进行赋值操作,只能在函数范围内改变局部变量指向的引用地址,但是不会改变原始地址的内容。因此,在changeValue2(...)函数内部的vo1和函数外的vo1虽然名字相同,但是实际上是不同的实例变量,只不过指向了和函数外的vo1同样的地址,所以当我们用vo1=... 对其进行赋值的时候,只不过是把函数内的临时变量指向了新的地址,并没有改变原始vo1内存地址中的内容。这就是在运行changeValue2(...)之后,vo1的值在main范围内仍然没有被修改的原因。而changeValue1里面是调用的ValueObject本身的function来更改其内容,因此是原始内存地址中的数据被更改了,所以是全局有效的。
分享到:
评论

相关推荐

    Java SE程序 界面传值问题

    Java SE程序 界面传值问题Java SE程序 界面传值问题Java SE程序 界面传值问题Java SE程序 界面传值问题Java SE程序 界面传值问题Java SE程序 界面传值问题Java SE程序 界面传值问题Java SE程序 界面传值问题Java SE...

    java中传值与传引用

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

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

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

    java及C++中传值传递、引用传递和指针方式的理解.docx

    ### Java及C++中传值传递、引用传递和指针方式的理解 在程序设计语言中,函数调用时参数的传递方式对理解程序的行为至关重要。本文将深入探讨Java与C++这两种广泛使用的编程语言中参数传递的方式,包括值传递、引用...

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

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

    JSP中java代码与js之间的传值

    - **通过JSP表达式语言(EL)**:使用EL表达式,如 `${javaVariable}`,可以直接在JavaScript代码中引用JavaBean或作用域内的变量。 2. **JavaScript到Java的传值**: - **表单提交**:通过JavaScript修改表单字段的...

    lotus domnio java代理传值

    "lotus domnio java代理传值"这个主题主要涉及如何在Java代码中创建和使用代理,并在代理之间传递参数。 首先,让我们了解一下Lotus Domino Java代理的基本概念。在Lotus Domino Designer中,Java代理是用Java语言...

    Java中引用类型传值的代码清单.pdf

    当我们讨论“引用类型传值”时,意味着在方法调用时,传递的是对象引用的一个副本,而不是对象本身。以下是对给定代码清单的详细解释: 1. `Circle.java` 文件定义了一个名为 `Circle` 的类,它包含一个 `double` ...

    java错误处理:java.lang.OutOfMemoryError: Java heap space

    ### Java 错误处理:java.lang.OutOfMemoryError: Java heap space 在Java应用程序开发过程中,经常遇到的一个问题就是内存溢出错误,特别是在处理大量数据或长时间运行的应用时。其中,“java.lang....

    传值传名传地址.zip

    总结起来,理解传值、传名(或传引用)和传地址的异同是编程基础的重要组成部分。它们影响着函数的可读性、效率以及程序的行为。在编写代码时,根据具体需求选择合适的参数传递方式,是提升代码质量的关键。

    解决java enctype multipart form-data文件上传传值问题

    ### 解决Java enctype "multipart/form-data" 文件上传传值问题 在Java Web开发中,处理文件上传是一项常见的任务。特别是当涉及到使用`multipart/form-data`作为表单的编码类型时,这种需求更为突出。本文将深入...

    简单的网页传值

    网页传值是Web开发中的基本操作,用于在不同的页面间传递数据,使用户的状态得以保持。本主题将深入探讨两种常见的方法:Cookie和Session。理解并掌握这两种技术对于构建动态和交互性强的网站至关重要。 首先,我们...

    Android NDK底层和java代码相互传值调用(实用经典Demo)

    在Android开发中,Java语言是主要的编程工具,但有时为了追求性能优化或者利用已有的C/C++库,我们会使用Android Native Development Kit (NDK)。NDK允许开发者在Android应用中集成原生代码,实现Java与C/C++之间的...

    Java并发编程:设计原则与模式(第二版)

    Java并发编程:设计原则与模式(第二版).pdf

    浅谈Java中方法的参数传值.pdf

    Java方法参数传值是Java编程中的基础知识点,涉及变量、数据类型和方法调用的机制。在Java中,数据类型分为基本数据类型和引用数据类型。基本数据类型包括布尔型(boolean)、字节型(byte)、短整型(short)、整型...

    Java经典面试题大全(带答案)

    ### Java经典面试题知识点解析 #### 一、单项选择题知识点解析 1. **Java的起源** - **知识点**:Java的历史和发展。 - **解释**:Java是由Sun Microsystems公司的James Gosling等人于1995年创建的。它是在C++的...

    java及C++中传值传递、引用传递和指针方式的理解

    引用传递类似于Java中的引用,但它不像Java那样创建引用副本,而是直接提供原始对象的别名。这意味着对引用参数的任何修改都会影响原始对象,如`ByRef`函数所示。指针传递则是传递对象地址,`ByPointer`函数通过解...

Global site tag (gtag.js) - Google Analytics