前面的更新已经提到过Java变量的定义规则与命名规则,这里对于变量进行更深入一步理解。
Java中根据变量的定义位置,可以分成两大类,每个大类又可以细分,具体的细分如下:
上图应该很好的表现了变量的分类的区分以及基本特性,成员变量指在类里面定义的变量,里面根据是不是以static修饰可以分为类变量与实例变量,成员变量可以不赋值直接使用,因为系统会自动添加一个默认值,这个默认值的规则和数组里的数组项的默认值的规则是一样的,byte short int long 是0,double float是0.0,char是'/U0000',boolean是false,里面的实例变量与类变量之间的区别是调用的方式不一样,以及生命周期不同;而在方法里定义的局部变量包括形参、方法局部变量、代码块局部变量,他们里面形参是不用赋值的,但是形参的值是由调用方法赋实参,再由系统进行赋值的,而其余两个都是要先赋值再使用的。
在了解了这些特性以后,用代码看看实参与形参的定义与调用:
class Demo{
//类成员变量
static int var1;
//实例成员变量
String var2;
void fun(int x){//形参
int y;
//方法局部变量
int z = 15;
// System.out.println(y);//编译报错,错误信息:局部变量尚未初始化
System.out.println(z);
}
{
//代码块局部变量
int y;
int z = 15;
// System.out.println(y);//编译报错,错误信息:局部变量尚未初始化
System.out.println(z);
}
}
public class Test03 {
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println(Demo.var1);//调用类变量-->输出0
System.out.println(demo.var2);//调用实例变量-->输出null
demo.fun(151);//调用方法时,给形参传值
// 注意:方法里的局部变量是访问不到的,只能在方法里访问
}
}
参数的分类还是很好理解的,下面就一个案例,分析一下 各种参数在内存里的存放位置与时间,正是因为这些存放的不同导致的这些变量的差异,先将案例的代码粘到下面:
class Person{
public static int eyeName;//类变量
public String name;//实例变量
}
public class Test04 {
public static void main(String[] args) {
Person p1 = new Person();//创建第一个对象
Person p2 = new Person();//创建第二个对象
p1.name = "张三";
p2.name = "李四";
p1.eyeName = 2;
System.out.println(p1.name);//张三
System.out.println(p2.name);//李四
System.out.println(p1.eyeName);//2
System.out.println(p2.eyeName);//2
}
}
先分析一个代码,类Person有两个变量,一个类变量,一个实例变量,在Test04的方法中,我们创建两个Person实例,分别给两个实例的实例变量赋值,然后给p1的类变量赋值,然后,我们输出这些变量,当然两个实例变量输出的都是我们赋的值,可是,类变量值设置了p1的,p2的没有设置,但是两个的都发生了改变,这是为什么?
原因我们也提到过,类变量是属于类的,不属于实例,所以尽管用实例去调用了,但是,这样的写法是特别的不推荐的,因为会给人引起误导,这一点《疯狂Java讲义》的作者也提到了,说用实例调用类变量,是Java中的一点缺陷,所以在编程的过程中要尽量的避免。下面,我们分别看看各个阶段的内存加载状态:
上面的图很好的说明了成员变量的内存存放方式,下面我们分析一下局部变量的内存机制:
局部变量很特殊,不属于类也不属于对象,而是属于方法或者代码块,所以存放在方法的栈内存中,先看一段代码,
void fun(){
int i = 15;
String s = "hello";
}
很简单的一个方法,我们看看图示,
通过上图应该很好的理解了。