`

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:java参数传递(超经典)

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

changeData(sb);

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

java参数传递(超经典)

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

strBuf.append("World!");

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

java参数传递(超经典)

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

After changeData(n), sb = Hello World!

再看看Test3这个程序。

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

java参数传递(超经典)

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

strBuf.append("World!");

而执行完这句后,

java参数传递(超经典)

通过上图可以看到,由于sbstrBuf中存放地址不一样了,所以虽然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;后:

java参数传递(超经典)

分享到:
评论

相关推荐

    jsp参数传递

    jsp中多个页面传输参数,超链接传输参数

    超轻量压缩传输js2java rpc框架(XtZPStream v1.0)

    2、支持复杂js对象作为入参:能够传递复杂的JavaScript Object对象作为调用参数, 在java中得到对应的Map对象 3、自动压缩、解压传递的数据:调用过程中传递的数据自动进行压缩传输,后台自动解压, 然后转换为Map...

    head first java

    方法参数与返回类型 值传递 Getters与Setters 封装 数组中的引用 习题 5 超强力方法 创建战舰游戏 简单版 编写伪码 测试 编写程序 完成版 用Math.random()产生随机数 预先输入好的程序 循环 类型转换 用Integer....

    张孝祥Java就业培训教程.pdf

    3.6 函数的参数传递 3.7 Static关键字 3.8 内部类 3.9 使用Java的文档注释 第4章 面向对象(下) 4.1 类的继承 4.2 抽象类与接口 4.3 对象的多态性 4.4 异常 4.5 包 4.6 访问控制 4.7 使用jar文件 第5章 多线程 5.1 ...

    Web服务器的java实现

    HTTP的请求一般是GET或POST命令(POST用于FORM参数的传递)。GET命令的格式为:  GET 路径/文件名 HTTP/1.0  文件名指出所访问的文件,HTTP/1.0指出Web浏览器使用的HTTP版本。  (3) 应答:Web浏览器提交请求后...

    超级有影响力霸气的Java面试题大全文档

    超级有影响力的Java面试题大全文档 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。...

    Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册

    消息是以参数的形式传递给某方法的。一个消息通常由三部分组成: 1. 消息传送到对象的名称。 2. 要执行的方法的名称。 3. 方法需要的任意参数。 2.2.4 类 类是一个蓝图或样板,定义了某种类型的所有对象的变量...

    深入Java Servlet网络编程

    10. 2 服务器端包含的参数传递 10. 3 服务器端包含的实例 第11章 Applet和Servlet通信 11. 1 Applet和Servlet通信概述 11. 2 Applet和Servlet的网络通信 11. 2. 1 初识Applet和Servlet网络通信 11. 2. 2 Applet和...

    Java2核心技术.part5

    5.4 远程方法中的参数传递 5.5 服务器对象激活 5.6 JavaIDL与CORBA 5.7 远程方法调用与SOAP 第6章 高级Swing 第7章 高级AWT 第8章 JavaBean构件 第9章 安全 第10章 国际化 第11章 本地方法 第12章 XML 第...

    java猜数字源码-eweb4j-framework:简单的Java网络框架

    超级方便的视图数据传递 充血模型 声明式事务、事务模板、事务嵌套 丰富的DAO封装类 多数据源、表关联 简单的 IOC 容器 MVC、ORM、IOC 可控开关 键值对配置文件支持 国际化支持 让我们看看它是如何做到的。 == 1. 独...

    Java2核心技术.part3

    5.4 远程方法中的参数传递 5.5 服务器对象激活 5.6 JavaIDL与CORBA 5.7 远程方法调用与SOAP 第6章 高级Swing 第7章 高级AWT 第8章 JavaBean构件 第9章 安全 第10章 国际化 第11章 本地方法 第12章 XML 第...

    Java2核心技术.part1

    5.4 远程方法中的参数传递 5.5 服务器对象激活 5.6 JavaIDL与CORBA 5.7 远程方法调用与SOAP 第6章 高级Swing 第7章 高级AWT 第8章 JavaBean构件 第9章 安全 第10章 国际化 第11章 本地方法 第12章 XML 第13章 注释

    Java2核心技术.part6

    5.4 远程方法中的参数传递 5.5 服务器对象激活 5.6 JavaIDL与CORBA 5.7 远程方法调用与SOAP 第6章 高级Swing 第7章 高级AWT 第8章 JavaBean构件 第9章 安全 第10章 国际化 第11章 本地方法 第12章 XML 第...

    Java2核心技术.part4

    5.4 远程方法中的参数传递 5.5 服务器对象激活 5.6 JavaIDL与CORBA 5.7 远程方法调用与SOAP 第6章 高级Swing 第7章 高级AWT 第8章 JavaBean构件 第9章 安全 第10章 国际化 第11章 本地方法 第12章 XML 第...

    Java2核心技术.part2

    5.4 远程方法中的参数传递 5.5 服务器对象激活 5.6 JavaIDL与CORBA 5.7 远程方法调用与SOAP 第6章 高级Swing 第7章 高级AWT 第8章 JavaBean构件 第9章 安全 第10章 国际化 第11章 本地方法 第12章 XML 第...

    java-servlet-api.doc

    当客户端发出请求时,Servlet引擎传递给Servlet一个ServletRequest对象和一个ServletResponse对象,这两个对象作为参数传递到service()方法中。 Servlet也可以执行ServletRequest接口和ServletResponse接口。...

    超完整FreeMarker中文教程,代码

    前言................................................................................................................................. 7 什么是FreeMarker? ................................................

    C++内存管理.doc

    因此要想成为C++高手,内存管理一关是必须要过的,除非放弃C++,转到Java或者.NET,他们的内存管理基本是自动的,当然你也放弃了自由和对内存的支配权,还放弃了C++超绝的性能。本期专题将从内存管理、内存泄漏、...

    Google Android SDK开发范例大全(完整版附部分源码).pdf

    8.1 HTTPGET/POST传递参数——HTTP连接示范 8.2 在程序里浏览网页——WebView.loadUrl 8.3 嵌入HTML标记的程序——WebView.loadData 8.4 设计前往打开网页功能——Intent与Uri.parse 8.5 将网络图像网址放入...

Global site tag (gtag.js) - Google Analytics