类成员变量和类变量

一般习惯称为实例变量和类变量,也有习惯叫实例变量和静态变量,总之几种变量类型比较简单,但是叫法各色各样

成员变量最常见,类中独立声明的变量,不在方法之内,而且没有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

发表评论