问题
先看一段代码,并写出输出结果
public class Test {
public static int a ;
public static void main(String[] args) {
name(a);
System.out.println(a);
}
public static void name(int a ){
a=20;
}
}
//输出结果:0
这段代码我拿着问了很多人,肯定有说结果是20的,毕竟基础都很薄弱。也有上班的同学,忙里偷闲回了一句“int默认值是0,a是值类型,方法赋值没用”,然后就留下一堆半斤八两的我们开始长篇大论,扔一堆其实自己也看不太懂的解释出来,最后再问一句,是这样吗?好在,经过一番讨论,对于这个问题也有了一点了解,所以写出来跟大家分享一下,也欢迎大家指正。
原理解释
基本数据类型赋值都属于值传递,值传递传递的是实实在在的变量值,是传递原参数的拷贝;值传递后,实参传递给形参的值,形参发生改变而不影响实参。
局部变量可以和全局变量重名,但是局部会屏蔽全局。
局部会屏蔽全局。个人理解,同时存在两个名称相同的局部变量和全局变量时,方法只对对局部变量进行操作,作用域只在方法体内,不能改变全局变量的值。
以上两个观点都可以解释上述代码中的问题。个人理解,方法的形参列表定义的a,相当于全局变量a的一个克隆体,虽然两个a长的一样,但形参列表里的a跟全局变量a是不同的个体,自体发生改变无法改变另外一个。
如果想在方法体中使用同名的全局变量,可以使用类名.全局变量的方式。
也就是说将方法体中的 a=20; 改为 Test.a=20; 则输出结果为20。
接下来看另外一段代码,并写出输出结果
public class Test {
public static int a ;
public static void main(String[] args) {
name(a);
System.out.println(a);
}
public static void name(int b ){
a=20;
}
}
//输出结果:20
如果直接贴出这段代码,相信大部分的人都会说出正确的结果,但是经过上面问题的讨论,肯定会有很多人想说WTF。其实问题很简单,方法体中的a与全局变量a是同一个体,name()方法就是一个简单的赋值方法。
此外,也有同学跟我提到说,Java储存变量在栈中,在执行方法体时,方法在栈中查找数据,因为全局变量先定义,局部变量后定义,所以根据“先进后出”的原则,方法会首先找到局部变量赋值,所以第一段代码输出结果为0。呃。。。听到这样的解释我是有点懵逼的。
- 首先,我认为Java中的被操作变量应该是明确的,而不是找到谁就是谁,如果被操作变量不明确,编译时应该会报错,可参考下面代码。
interface A{
int x = 0;
}
class B{
int x = 1;
}
class C extends B implements A{
public void pX(){
System.out.println(x);
}
public static void main(String[] args){
new c().pX();
}
}
//编译时报错:The field x is ambiguous
- 不知道大家对这个观点怎么看,难道这是从JVM 的角度解释了局部变量屏蔽全局变量的机理?望大神告知
为了帮助大家更好的理解这个问题,贴两篇博客出来供大家参考,其实相关的参考博客有很多,有的分析的也十分详细,但我选择博客的主要出发点是希望可以用最简单的方式帮助大家理解,以供参考。
1、关于值类型和引用类型
JAVA中值类型和引用类型的不同?
2、关于局部变量和全局变量
局部变量和全局变量的区别
欢迎大家共同讨论!