一般习惯称为实例变量和类变量,也有习惯叫实例变量和静态变量,总之几种变量类型比较简单,但是叫法各色各样
成员变量最常见,类中独立声明的变量,不在方法之内,而且没有static来修饰
类变量,也是在类中独立声明的变量,不在方法之内,但是有static来修饰
局部变量,这个意思比较大众化,类中方法内部声明的变量
它们之间的异同点还是不少,最大的差异就是实例变量是属于某个对象的属性,必须创建了实例化对象,这时候实例变量才会被分配空间,才能使用这个实例变量;静态变量不属于某个实例对象,而是属于类,因此也叫类变量,只要程序加载了类,不需要创建任何实例对象,静态变量就会被分配空间,那么静态变量就可以来使用了,如此一来实例变量必须创建对象之后,才能通过这个对象来引用,而静态变量是可以直接通过类名来引用
看个简单例子
class Num { static int number; public void setNumber(int number) { this.number = number; } public int getNumber() { return number; } } public class Main { public static void main(String[] args) { Num n1 = new Num(); n1.setNumber(10); System.out.println(n1.getNumber()); Num n2 = new Num(); n2.setNumber(100); System.out.println(n2.getNumber()); System.out.println(n1.getNumber()); } }
这里新建了两个对象,分别对类变量number的值进行了更新,假如这是一个实例变量,那进行实例化之后,变量就属于各个对象私有了,各自改变各自的值,就不会影响到其它对象;但这里是一个类变量,是属于类的属性,所有对象共有的,系统对于每个类变量只分配一次存储空间,任何其中一个对象将它的值进行了更新,其它对象获取到的都将是该变量更新后的值
这里输出的结果
10 100 100
加一句通过类名引用该静态变量,更好地理解所有对象共享一个变量拷贝
class Num { static int number; public void setNumber(int number) { this.number = number; } public int getNumber() { return number; } } public class Main { public static void main(String[] args) { System.out.println(Num.number); Num n1 = new Num(); n1.setNumber(10); System.out.println(n1.getNumber()); System.out.println(Num.number); Num n2 = new Num(); n2.setNumber(100); System.out.println(n2.getNumber()); System.out.println(Num.number); System.out.println(n1.getNumber()); System.out.println(Num.number); } }
初始值默认赋值为0,后面每次发生了静态变量更新,通过类引用的变量值随之改变
下面来一道题
class Num { final static Num num = new Num(5); static int number = 20; int currentNum; public Num(int x) { currentNum = number - x; } } public class Main { public static void main(String[] args) { System.out.println(Num.num.currentNum); } }
这里类的实例是类的成员变量,number是一个类变量,currentNum也是一个成员变量,最终需要输出的,是通过Num类型的num引用变量来访问currentNum变量
这里输出的结果是-5而不是15
这里需要好好捋一捋
通过标准调用方式,类名调用静态变量Num.num,而这里的num是一个引用变量,最终访问成员变量输出;这里对于初始化的细节需要走一遍
首先用到了Num类,对类进行初始化,对类变量进行存储空间的分配
然后对类变量进行初始化,这里有num和number,先num,new一个堆对象赋给num,同时会调用Num(5),具体是调用
public Num(int x) { currentNum = number - x; }
这里x传值为5,number是类变量,本来是准备下一步进行初始化赋值的,此刻还没赋值,但是由于是类变量,默认值会置为0,因此这时候currentNum = 0 – 5 = -5
接着再来进行另一个类变量number的初始化,赋值为20,可此刻已经对currentNum的值没啥影响了
因此输出结果为-5
假如给number变量也加一个final
class Num { final static Num num = new Num(5); final static int number = 20; int currentNum; public Num(int x) { currentNum = number - x; } } public class Main { public static void main(String[] args) { System.out.println(Num.num.currentNum); } }
这里都是final变量,而且都声明变量的时候指定了初始化的值,也就是在编译前已经确定了初始化的值,那么final变量可以理解成宏定义来处理,在编译阶段已经进行了宏替换,也就是编译就已经知道了值
因此此处number早早就变成了20,最终的结果是15
一般来说:
1:static变量在静态代码中进行初始化
2:final变量在编译阶段完成了初始化
3:常用变量在构造函数中进行初始化
程序运行基本按照类加载,静态代码运行,静态变量初始化,对应构造函数运行来执行
直接将num和number两个静态变量位置对换
class Num { static int number = 20; final static Num num = new Num(5); int currentNum; public Num(int x) { currentNum = number - x; } } public class Main { public static void main(String[] args) { System.out.println(Num.num.currentNum); } }
此时在调用Num(5)的时候,number已经提前初始化完成,这个时候才是返回15