很久以来我都不是很清楚static修饰的成员变量,为什么总要煞有介事的写成全大写,比如下面这样:
package com.example.demo;
public class Human {
private String name;
public static int AGE;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
看起来和C语言里写的全局变量差不多,而事实上我们在开发过程中有时候就是把static修饰的变量当做全局变量来用。那么static修饰的变量到底有什么不同?
其实一句话就能描述其不同:
static变量是属于类的,不是属于对象的。
在执行Humam human = new Human();这一语句时,在内存中发生的事情其实还挺多的,首先类加载器会把类加载到内存里,此时的堆内存是这样的:
图1这个时候AGE,static修饰的AGE就已经在内存中了,而且有一个默认值0,但是这个阶段还没有对象被创建出来,下一个阶段就要开始创建类了:
图2此时对象就被创建出来了,但是name属性还是没有值,这是正常的,我们没有初始化。
下面这段代码实例化了两个对象,并且赋值:
package com.example.demo;
public class Test {
public static void main(String[] args) {
Human human1 = new Human();
Human human2 = new Human();
human1.setName("lee");
human2.setName("wei");
human1.AGE = 11;
System.out.println(human2.AGE);
}
}
此时的堆内存变成了这个样子:
图3画的比较粗糙,但是能够说明几个问题:
- human1和human2是两个对象,其name属性指向两个不同的String对象;
- AGE作为static修饰的变量,独立于对象,而属于类。
上面的代码执行结果是打印出了11,有一些人确实会费解,因为明明没有给human2的AGE赋值呀,为什么?
还是那句话,AGE因为被static修饰,是属于类而不属于对象的。因此上面的这两句:
human1.AGE = 11;
System.out.println(human2.AGE);
一般的IDE一定会报一个警告,如下图:
图4这句警告提醒我们,使用类去调用这个AGE,而不是用类的实例,因此上面的代码改成这样,就完美了:
package com.example.demo;
public class Test {
public static void main(String[] args) {
Human human1 = new Human();
Human human2 = new Human();
human1.setName("Lee");
human2.setName("Wei");
Human.AGE = 11;
System.out.println(Human.AGE);
}
}
这样的代码就消除了歧义,因为static修饰的变量是属于类本身而不是类实例的。其实我觉得Java发展到今天,应该将我刚才写的用对象访问static变量的写法直接编程编译期异常,这样更便于理解。
网友评论