`

深入理解Java的方法调用一(值传递和引用传递)

阅读更多

众所周知Java的参数传递也分为值传递和引用传递

值传递

 

public class MethodAndParam {
	static void swap(int a,int b){
		int c = a;
		a = b;
		b =c;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		int a = 1 ,b =2;
		swap(a, b);
		System.out.println(a+","+b);

	}

}

 其结果大家都知道,a、b的值没有交换成功。

 

 

引用传递

 

	
	static void addA(StringBuffer sBuf){
		sBuf.append("A");
	}


	/**
	 * @param args
	 */
	public static void main(String[] args) {
		StringBuffer sBuf = new StringBuffer();
		addA(sBuf);
		System.out.println(sBuf.toString());
	}

 因为是引用传递,能找到对象的真实地址从而改变对象的值,其输出结果为A。

 

 

 

	static void addA(String str){
		str = str + "A";
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		String str = "";
		addA(str);
		System.out.println(str);
	}

 问题一:同样是引用传递,但结果并没有输出A,而是输出了空串,这是为什么呢?

 

 

我们将StringBuffer的例子改造如下:

 

	static void addAByNew(StringBuffer sBuf){
		sBuf = new StringBuffer();
		sBuf.append("A");
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		StringBuffer sBuf = new StringBuffer();
		addAByNew(sBuf);
		System.out.println(sBuf.toString());	
	}

 同样上面的运行结果也没有输出A,而是输出了空串。如果传递的是引用,方法内部的代码sBuf = new StringBuffer()将引用指向了新的地址空间,在新的地址空间里append("A")。

问题二:在方法内部对引用的改变为什么没有影响到外部的对象?

 

 

对于问题一,大家可以看一下String对象的源码

 

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
{
    /** The value is used for character storage. */
    private final char value[];

    /** The offset is the first index of the storage that is used. */
    private final int offset;

    /** The count is the number of characters in the String. */
    private final int count;

 String类是final修饰的,表示不能被继承。对于被final修饰的属性的赋值有如下几种方式:

 

    1. 如果有static修饰的属性,可以在static{}块里赋值

    2. 如果没有static修饰,可以在代码块{}里赋值

    3. 在定义变量时赋值

    4. 在构造方法里赋值

即一旦一个对象创建,其final修饰的属性值将不可改变,而String对象中存放值的value数组则是final修饰的,我们可以理解为:一个String对象的值改变后,它已经不是原来的它了。理解了String对象的不变性后可知问题一和问题二背后是同一个原因。

 

从JVM出发来看方法的调用

      栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,每一个方法从调用开始到执行完成的过程,就对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。

      栈帧包括了局部变量表、方法返回地址等信息。其中局部变量表是一组变量值空间,用于存放方法参数和方法内部定义的局部变量。



     现在可以回答问题二了:参数的引用传递不是单纯的将对象的引用传递给一个方法,而是将对象引用的地址传递给局部变量表里的参数引用,当在方法内部改变引用的地址时,只会影响方法内部的引用,而不会影响到方法外部的变量。但如果改变的是引用地址的值,方法内外的引用都会受影响。

 

 

  • 大小: 48.3 KB
1
1
分享到:
评论
8 楼 zhdkn 2013-05-14  
m635674608 写道
zhdkn 写道
m635674608 写道
zhdkn 写道
m635674608 写道
zhdkn 写道
m635674608 写道
string对象其实是可以变的、、

String对象的不可变性:是指它不可在原来的地址改变其值,一旦一个String对象的值改变,其实是产生了一个新的String对象

有种方法,改变对象的值,也不会产生新的string对象!

那种方法?

反射,,呵呵

真心不会,求代码指导。第一次听说反射能改变原地址Stirng的值。

http://m635674608.iteye.com/blog/1768880

服了
7 楼 m635674608 2013-05-14  
zhdkn 写道
m635674608 写道
zhdkn 写道
m635674608 写道
zhdkn 写道
m635674608 写道
string对象其实是可以变的、、

String对象的不可变性:是指它不可在原来的地址改变其值,一旦一个String对象的值改变,其实是产生了一个新的String对象

有种方法,改变对象的值,也不会产生新的string对象!

那种方法?

反射,,呵呵

真心不会,求代码指导。第一次听说反射能改变原地址Stirng的值。

http://m635674608.iteye.com/blog/1768880
6 楼 zhdkn 2013-05-13  
m635674608 写道
zhdkn 写道
m635674608 写道
zhdkn 写道
m635674608 写道
string对象其实是可以变的、、

String对象的不可变性:是指它不可在原来的地址改变其值,一旦一个String对象的值改变,其实是产生了一个新的String对象

有种方法,改变对象的值,也不会产生新的string对象!

那种方法?

反射,,呵呵

真心不会,求代码指导。第一次听说反射能改变原地址Stirng的值。
5 楼 m635674608 2013-05-13  
zhdkn 写道
m635674608 写道
zhdkn 写道
m635674608 写道
string对象其实是可以变的、、

String对象的不可变性:是指它不可在原来的地址改变其值,一旦一个String对象的值改变,其实是产生了一个新的String对象

有种方法,改变对象的值,也不会产生新的string对象!

那种方法?

反射,,呵呵
4 楼 zhdkn 2013-05-13  
m635674608 写道
zhdkn 写道
m635674608 写道
string对象其实是可以变的、、

String对象的不可变性:是指它不可在原来的地址改变其值,一旦一个String对象的值改变,其实是产生了一个新的String对象

有种方法,改变对象的值,也不会产生新的string对象!

那种方法?
3 楼 m635674608 2013-05-13  
zhdkn 写道
m635674608 写道
string对象其实是可以变的、、

String对象的不可变性:是指它不可在原来的地址改变其值,一旦一个String对象的值改变,其实是产生了一个新的String对象

有种方法,改变对象的值,也不会产生新的string对象!
2 楼 zhdkn 2013-05-13  
m635674608 写道
string对象其实是可以变的、、

String对象的不可变性:是指它不可在原来的地址改变其值,一旦一个String对象的值改变,其实是产生了一个新的String对象
1 楼 m635674608 2013-05-13  
string对象其实是可以变的、、

相关推荐

Global site tag (gtag.js) - Google Analytics