`
NEO_ONE
  • 浏览: 48676 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

参数传递

    博客分类:
  • Java
 
阅读更多

 Java中的参数传递机制一直以来大家都争论不休,究竟是“传值”还是“传址(传引用)”,争论的双方各执一词,互不相让。不但“菜鸟”们一头雾水,一些“老鸟”也只知道结果却说不出所以然来。我相信看过下面的内容后,你就会明白一些。

先看基本类型作为参数传递的例子:

public class Test1 {

       public static void main(String[] args) {

        int n = 3;
        System.out.println("Before change, n = " + n);
                changeData(n);

        System.out.println("After changeData(n), n = " + n);

    }     
       public static void changeData(int nn) {

        n = 10;
    }
}

 

我想这个例子大家都明白,基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的,输出的结果证明了这一点:

Before change, n = 3

After changeData(n), n = 3

 

那么,我们现在来看看对象作为参数传递的例子,这也是大家争论的地方。

public class Test2 {

       public static void main(String[] args) {

        StringBuffer sb = new StringBuffer("Hello ");

        System.out.println("Before change, sb = " + sb);

        changeData(sb);

        System.out.println("After changeData(n), sb = " + sb);

    }

      

       public static void changeData(StringBuffer strBuf) {

        strBuf.append("World!");

    }

}

 先看输出结果:

Before change, sb = Hello

After changeData(n), sb = Hello World!

从结果来看,sb的值被改变了,那么是不是可以说:对象作为参数传递时,是把对象的引用传递过去,如果引用在方法内被改变了,那么原对象也跟着改变。从上面例子的输出结果来看,这样解释是合理。

现在我们对上面的例子稍加改动一下:

public class Test3 {

       public static void main(String[] args) {

        StringBuffer sb = new StringBuffer("Hello ");

        System.out.println("Before change, sb = " + sb);

        changeData(sb);

        System.out.println("After changeData(n), sb = " + sb);

    }

      

       public static void changeData(StringBuffer strBuf) {

           strBuf = new StringBuffer("Hi ");

           strBuf.append("World!");

    }

}

 按照上面例子的经验:对象作为参数传递时,是把对象的引用传递过去,如果引用在方法内被改变了,那么原对象也跟着改变。你会认为应该输出:

Before change, sb = Hello

After changeData(n), sb = Hi World!

但运行一下这个程序,你会发现结果是这样的:

Before change, sb = Hello

After changeData(n), sb = Hello

这就是让人迷惑的地方,对象作为参数传递时,同样是在方法内改变了对象的值,为什么有的是改变了原对象的值,而有的并没有改变原对象的值呢?这时候究竟是“传值”还是“传引用”呢?

下面就让我们仔细分析一下,来揭开这中间的奥秘吧。

先看Test2这个程序:

StringBuffer sb = new StringBuffer("Hello ");

这一句执行完后,就会在内存 的堆里生成一个sb对象,请看图1:图1

如图1所示,sb是一个引用,里面存放的是一个地址“@3a”(这个“@3a”是我举的代表内存地址的例子,你只需知道是个内存地址就行了),而这个地址正是“Hello ”这个字符串在内存中的地址。

changeData(sb);

执行这一句后,就把sb传给了changeData方法中的StringBuffer strBuf,由于sb中存放的是地址,所以,strBuf中也将存放相同的地址,请看图2:

图2

此时,sb和strBuf中由于存放的内存地址相同,因此都指向了“Hello”。

strBuf.append("World!");

执行changeData方法中的这一句后,改变了strBuf指向的内存中的值,如下图3所示:

图3

所以,Test2 这个程序最后会输出:

After changeData(n), sb = Hello World!

 

再看看Test3这个程序。

在没有执行到changeData方法的strBuf = new StringBuffer(“Hi “);之前,对象在内存中的图和上例中“图2”是一样的,而执行了strBuf = new StringBuffer(“Hi “);之后,则变成了:

图4

此时,strBuf中存放的不再是指向“Hello”的地址,而是指向“Hi ”的地址“@3b” (同样“@3b”是个例子)了,new操作符操作成功后总会在内存中新开辟一块存储区域。

       strBuf.append("World!");

       而执行完这句后,

图5

通过上图可以看到,由于sb和strBuf中存放地址不一样了,所以虽然strBuf指向的内存中的值改变了,但sb指向的内存中值并不会变,因此也就输出了下面的结果:

After changeData(n), sb = Hello

 

String类是个特殊的类,对它的一些操作符是重载的,如:

String str = “Hello”; 等价于String str = new String(“Hello”);

String str = “Hello”;

str = str + “ world!”;等价于str = new String((new StringBuffer(str)).append(“ world!”));

因此,你只要按上面的方法去分析,就会发现String对象和基本类型一样,一般情况下作为参数传递,在方法内改变了值,而原对象是不会被改变的。

 

综上所述,我们就会明白,在Java中对象作为参数传递时,是把对象在内存中的地址拷贝了一份传给了参数。

你可以试着按上面的画图法分析一下下面例子的结果,看看运行结果与你分析的结果是否一样:

public class Test4 {

       public static void main(String[] args) {

        StringBuffer sb = new StringBuffer("Hello ");

        System.out.println("Before change, sb = " + sb);

        changeData(sb);

        System.out.println("After changeData(n), sb = " + sb);

    }

      

       public static void changeData(StringBuffer strBuf) {

           StringBuffer sb2 = new StringBuffer("Hi ");

           strBuf = sb2;

           sb2.append("World!");

    }

} 

     提示:

         执行完strBuf = sb2;后:

图6

分享到:
评论

相关推荐

    mybatis 动态sql及参数传递

    参数传递 单个参数传递 多个参数传递 传入单个实体(JavaBean/Map) 传入多个实体 传入集合 使用场景 在实际开发过程中,我们往往需要编写复杂的SQL语句,拼接稍有不注意就会导致错误,Mybatis给开发者提供了动态SQL,...

    kettle实现多参数传递并且循环加载数据.zip

    本项目"Kettle实现多参数传递并且循环加载数据.zip"显然是一个利用Kettle解决复杂业务逻辑的示例,特别关注了参数传递和数据的循环处理。以下将详细解释相关知识点。 1. **Kettle参数传递**: 在Kettle中,参数...

    c# 调用C++编写 的DLL函数各种参数传递问题。

    C# 调用 C++ 编写的 DLL 函数各种参数传递问题 在 C# 调用 C++ 编写的 DLL 函数时,参数传递是一个非常重要的部分。这篇文章将详细介绍 C# 调用 C++ 编写的 DLL 函数各种参数传递问题,包括不返回值的参数、带...

    Matlab GUI参数传递方式

    ### Matlab GUI参数传递方式详解 #### 一、全局变量 全局变量是一种常见的数据共享方法,尤其是在Matlab GUI设计中。这种方式简单直接,适用于GUI内部不同控件之间以及不同GUI之间的数据共享。 **特点:** - **...

    访问网站的参数传递代码

    在互联网应用中,参数传递是实现页面间数据交互的关键技术,尤其在动态网站和Web应用程序中更为重要。当用户在网站上浏览时,有时需要在不同的页面之间传递信息,如搜索查询、用户登录状态或者购物车的商品信息等。...

    两个网页之间参数传递例子

    在互联网应用中,网页间的参数传递是至关重要的,它使得用户在浏览不同页面时能够保持信息的连贯性。这个例子将深入探讨几种常见的网页间参数传递方法,以帮助你理解这一关键概念。 首先,我们有URL查询字符串。当...

    使用一般参数传递方式,实现简单计算器的加减乘除后端接口功能。

    本主题聚焦于使用“一般参数传递方式”来创建一个能够处理加、减、乘、除运算的后端接口。这里我们将深入探讨如何实现这个功能,并通过具体的HTTP请求地址`Http://localhost:8080/simplecalculator`来演示其工作原理...

    JNI 参数传递 Android 自定义对象

    本篇文章将深入探讨JNI中参数传递的基本数据类型、自定义对象以及系统对象。 一、基本数据类型的参数传递 在JNI中,基本数据类型如int、float、char等的传递相对简单。Java中的基本类型在C/C++中都有对应的类型。...

    VB参数传递方式判别与解题应用

    VB参数传递方式是编程中一个基础但重要的概念,尤其是在Visual Basic中。VB中的参数分为实参(实际参数)和形参(形式参数),实参是在调用过程时提供的,而形参是在过程定义时声明的。当调用过程时,实参与形参通过...

    JSF中文教程+JSF参数传递方式

    通过学习这个教程,你将能够熟练地配置JSF环境,创建和管理Bean,使用Facelets创建动态视图,以及掌握各种参数传递技巧,从而开发出高效且易于维护的JSF应用程序。 总之,JSF是一个强大且灵活的Web开发框架,它简化...

    Qt 窗体之间的参数传递.rar

    本文档将详细讲解如何在Qt窗体之间进行参数传递,以实现更加灵活和功能丰富的应用。 首先,我们来看“Qt 窗体之间的参数传递(窗体B的参数传给窗体A).txt”这个主题。在Qt中,有多种方法可以将一个窗体的数据传递...

    c# 参数传递,参数调用

    在C#编程语言中,参数传递和参数调用是核心概念,它们关乎着函数和方法如何接收和处理数据。理解这些概念对于编写高效且可维护的代码至关重要。本篇文章将深入探讨C#中的参数传递机制及其应用。 首先,我们要了解...

    C#跨窗体参数传递

    在C#编程中,跨窗体参数传递是应用程序设计中常见的需求,特别是在开发具有多个界面的桌面应用时。本主题将深入探讨如何在不同的窗体之间有效地传递数据,以实现功能如从一个窗体的文本框输入数据并在另一个窗体上...

    关于C语言中函数调用和参数传递机制的探讨.txt

    ### 关于C语言中函数调用和参数传递机制的探讨 在C语言中,函数是程序的基本构建单元之一,它们不仅能够实现代码的重用,还能通过参数传递机制实现数据的有效交互。本文将深入探讨C语言中的函数调用机制以及参数...

    Linux系统kernel参数传递方式详细解析

    ### Linux系统Kernel参数传递方式详细解析 #### 一、引言 在Linux系统中,内核启动时可以接收一系列参数,这些参数对于系统的初始化过程至关重要。例如,它们可以帮助内核了解如何配置硬件设备、确定系统运行模式...

    ireport使用subdataset主表和子数据集进行参数传递

    本话题将详细探讨如何在 iReport 中使用 `subdataset`(子数据集)与主数据集配合,以实现参数传递,从而实现动态的数据过滤。 首先,我们需要理解主数据集和子数据集的概念。主数据集是报表的基础,它通常对应于一...

    WPF程序中RDLC报表的使用及参数传递

    现在,我们来到参数传递的部分。在RDLC报表中,参数用于根据用户输入或代码动态筛选数据。在VS2010的报表设计器中,可以创建报表参数,并在数据源查询中使用它们。在WPF应用中,通过`ReportViewer`的`SetParameters`...

    C、C++函数参数传递方式.pdf

    C和C++中的函数参数传递方式主要分为值传递、指针传递和引用传递。这些方式决定了参数在函数调用时的传值行为,以及它们在函数执行后是否能够影响原始数据。下面详细解释这些传递方式的知识点。 1. 值传递(Call by...

Global site tag (gtag.js) - Google Analytics