方法中的局部变量

直接上例子

1.方法中,局部变量为基本类型

public class BaseChange {

	static void change(int a) {
		a += 5;
	}

	public static void main(String[] args) {
		int a = 1;
		change(a);
		System.out.println(a);
	}
}

得到的结果是 1。

2.方法中,局部变量为数组

	static void changeArr(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			arr[i] += 100;
		}
	}

	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4 };
		changeArr(arr);
		System.out.println(Arrays.toString(arr));
	}

得到的结果是:

[101, 102, 103, 104]

3.方法中,局部变量为String

	private static void change(String s) {
		s += "123";
	}

	public static void main(String[] args) {
		String s = "abc";
		change(s);
		System.out.println(s);
	}

得到的结果是:

abc

4.方法中,为自定义对象

Foo

public class Foo {
	private int a;
	private int b;

	public int getA() {
		return a;
	}

	public void setA(int a) {
		this.a = a;
	}

	public int getB() {
		return b;
	}

	public void setB(int b) {
		this.b = b;
	}

	@Override
	public String toString() {
		return "Foo [a=" + a + ", b=" + b + "]";
	}

}

测试类:

	static void changeFoo(Foo foo) {
		foo.setA(100);
		foo.setB(200);
	}

	public static void main(String[] args) {
		System.out.println("--change object-");
		Foo foo = new Foo();
		System.out.println(foo);
		changeFoo(foo);
		System.out.println(foo);
	}

得到的结果是:

--change object-
Foo [a=0, b=0]
Foo [a=100, b=200]


通过上面4个例子,可以得出以下结论:

1.当方法中的参数为int等基本类型时候,方法结束,值不变;

2.当方法中参数为String的时候,方法结束,值也不变;

3.当方法中参数为对象(自定义对象和数组),方法技术,值发生了变化。


方法以栈帧的形式被虚拟机加载到虚拟栈里面,每个线程单独的管理自己的虚拟栈,所以,多个线程调用同一个方法,是相互不干扰的(前提不对全局的数据修改);

方法结束的时候,栈帧退出虚拟机栈。此时,所有的方法中的入参的声明周期就结束了。


然后来回顾上面4段代码:

第一段代码:

1.当main中调用 int a=1的时候,基本变量a入虚拟栈

2.当调用方法change的时候,change方法栈帧入栈,局部变量a在栈帧上操作a+=5

3.当change方法结束的时候,栈帧退栈,打印a的值,a仍然是1。

因为java中,基本类型就是存储在虚拟栈中的。当然如果是全局变量,或者静态变量,至少可以肯定的是,不是存储在线程私有的虚拟栈上面的。


第二段代码和第四段代码

把他们放在一起讲,是笔者粗糙的认为,数组也是对象,所以直接放在一起解释。对于对象,虚拟机栈中存储的是该对象的应用,对象在堆上分配内存。

1.首先,方法进入前,变量引用入虚拟机栈,实际内容入堆,引用指向内容,且内容被初始化x:(当然,虚拟机实际的存储模型里面,还有一个类的信息,但是,数据确实是在堆里修改的)


2.当调用change方法的时候,引用作为参数传输到栈帧中,这时,两个引用同时都指向对象,然后,方法中进行操作,绿色框框中的引用将对象的值改为M

3.方法结束,栈帧退栈

因此,最后打印的结果,发生了变化,感觉是方法里面把值修改了。


再来看第三段代码:

我们先假设,String的值分配在堆上,但实际上(String有可能被分配在方法代,书上说的)。

String是一种特殊的对象,在堆上的表现是不可动态扩展的,就是如果 a="1"执行了a+="2"的操作,那么,堆上会产生两个String对象,一个是"1",一个是"2"。(java在编译的过程中,高版本的或许会将a="1",a+="2"的这种代码进行优化,不过,并不妨碍我们分析String作为参数传递到方法中).

ok,现在来进行分析代码:

1.首先String s="abc",此时,虚拟栈上会有一个s的变量引用,堆上有一个“abc”的对象,s的变量引用指向堆上的"abc"

2.调用change方法,栈帧入栈,参数栈,蓝色的引用作为参数传递给绿色的引用,这是,他们指向同一个对象:

3.方法中,执行s+="123",前面有说到,String比较特殊,他不会像其他对象一样,在内部进行修改,而是新分配一块内存。这是可以看到,方法中的引用和蓝色的引用,已经指向的不是同一个对象了。

4.方法执行完毕,栈帧退栈:

所以,最终输出的结果,仍然是"abc"。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章