Java中的静态变量&静态方法

Posted _陈肆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的静态变量&静态方法相关的知识,希望对你有一定的参考价值。

静态变量&静态方法

        静态变量又叫做类变量,静态方法又被称为类方法——均被static修饰

        未被static修饰的成员变量和方法分别被称为实例变量实例方法

(1)静态方法中不需要它所属类的任何实例就可以访问,所以在静态方法中不可以使用this关键字

(2)静态方法中不可直接访问所属类的实例变量和实例方法,但可以直接访问所属类的静态变量和静态方法

        如图所示,如果在静态方法中想要直接访问所属类的实例变量和实例方法或使用this关键字,编译器都会报错

(3)静态变量(方法)的访问方式:类名.变量名(方法名)

         实例变量(方法)需要先将类实例化后才可访问:对象名.变量名(方法名)

         如图所示,未实例化时使用“类名.变量名(方法名)”就可以直接访问静态变量(方法),但无法访问相应类的实例变量和实例方法

        如图所示,当将类实例化后,使用“对象名.变量名(方法名)”就可以直接访问实例变量(方法),但无法访问相应类的静态变量和静态方法

 (4)在内存中,实例/静态成员的存储形式大致如图

        所有静态成员共享一份内存——静态变量某种意义上具有全局性质

        而不同实例间的实例变量彼此互不干涉

详解:         

        当类的字节码文件被加载到内存时,类的实例方法不会被分配入口地址。当该类创建对象后,类中的实例方法才分配入口地址,从而实例方法可以被类创建的任何对象调用执行。
        类方法在该类被加载到内存时,就分配了相应的入口地址。从而类方法不仅可以被类创建的任何对象调用执行,也可以直接通过类名调用。 类方法的入口地址直到程序退出时才被取消。
注意:
        当我们创建第一个对象时,类中的实例方法就分配了入口地址,当再创建对象时,不再分配入口地址。
        也就是说,方法的入口地址被所有的对象共享,当所有的对象都不存在时,方法的入口地址才被取消。

总结:
        类变量和类方法与类相关联,并且每个类都会出现一次。 使用它们不需要创建对象。
        实例方法和变量会在每个类的实例中出现一次。

        以下是一个代码范例:

public class staticclass 
    public static int count = 0; //静态变量
    public int num =0; //非静态变量
    public static void method1() //静态方法
        System.out.println("正在访问静态方法(count++)....");
        System.out.println("\\tpre-count = "+count);
        count++;
        //num++; //静态方法中不可以访问实例变量
        //method2();  //静态方法中不可以访问实例方法
        //System.out.println(this.num); //静态方法中不可以使用this关键字
        System.out.println("\\tpst-count = "+count);
    
    public void method2() //实例方法
    
        System.out.println("正在访问实例方法(count+2,num+3)....");
        System.out.println("\\tpre-count = "+count);
        System.out.println("\\tpre-num = "+num);
        count+=2;
        num+=3;
        System.out.println("\\tpst-count = "+count);
        System.out.println("\\tpst-num = "+num);
    

    public static void main(String[] args) 
        System.out.println("初始时,count = "+staticclass.count); //访问静态变量:类名+变量名
        staticclass.method1();//访问静态方法:类名+变量名
        staticclass a = new staticclass();
        System.out.println("\\na未操作前,count = "+staticclass.count);
        System.out.println("         num = "+a.num);
        a.method2();
        staticclass b = new staticclass();
        System.out.println("\\nb未操作前,count = "+staticclass.count);
        System.out.println("         num = "+b.num);
        b.method2();
    

 运行结果如图,可印证以上三点:

Android-Java-静态变量与静态方法&普通变量与普通方法(内存图 完整版)

描述Student对象:

package android.java.oop12;

// 描述Student对象实体
public class Student {

    private String name;

    private int age;

    protected static String country = "CN";

    private Student() {}

    public Student(String name, int age) {
        /**
         * 通过拿到对象引用的地址(9998#==this),去操作 堆区内存的 name属性  age属性
         */
        this.name = name;
        this.age = age;
    }

    public void showValue() {
        /**
         * 通过拿到对象引用的地址(9998#==this),去操作 堆区内存的 name属性  age属性
         */
        System.out.println("name:" + this.name + " age:" + age);
    }

    public static void printlnCountry() {
        /**
         * 通过类名就可用拿到 ---> 方法区(共享数据区) --> 中的 静态区 里面的 --> 静态数据 ,都是共享的
         */
        System.out.println("country:" + Student.country);
        System.out.println("country:" + country);
    }

}

 

main测试方法:

package android.java.oop12;

public class TestDemo {

    public static void main(String[] args) {

        /**
         * 实例化Student对象         new Student("张三", 89);
         * 拿到实例化对象引用的地址    Student student == 9998#
         */
        Student student = new Student("张三", 89);

        /**
         * 通过拿到对象引用的地址(9998#==this),去调用showValue()方法
         */
        student.showValue();

        /**
         * 直接调用 静态区 共享的 printlnCountry() 方法
         */
        Student.printlnCountry();
    }

}

 

执行结果:

 

 

以上案例对应的内存图:

 

 

1. 执行 java TestDemo   是给JVM发送指令,和JVM说:把这个 TestDemo.class 去执行;

 

2.JVM就去执行 TestDemo.class 文件里面的字节码,首先第一步 是把 TestDemo.class字节码加载进内存;

 

3.第二步,会把TestDemo 静态数据 分配到 静态区里面去;

 

4.第三步,main方法进栈,是直接把静态区里面的 TestDemo --> main 方法拿过来进栈运行;

 

5.第四步,new Student("张三", 89);

 

6.第五步,注意:非常重要的点 要记住 ,那就是在 new Student("张三", 89); 的时候才把,Student.class加载进内存中的---> 存放区;

 

7.第六步,分配Student静态数据到--->静态区;

 

8.第七步,在堆内存中开辟 Student对象空间,并分配对象地址,并给变量赋初始值 null 0 等;

 

9.第八步:构造方法Student(name, age) 进栈, 第九步:构造方法Student(name, age)弹栈;

 

10.第十步,在堆内存中,name age 属性 被赋值完毕;

 

11.第十一步,new Student(name, age); 后 得到一个对象引用地址 给student变量;

 

12.第十二步,调用 student.showValue();

 

13.第十三步:showValue()方法进栈, 并通过this去操作name、age属性,  第十四步:showValue()方法弹栈;

 

14.第十五步:;

 

15.第十六步:printlnCountry()方法进栈,并直接去访问 共享的 country 变量,  第十七步:printlnCountry()方法弹栈;

 

16.第十八步:main方法执行完毕,弹栈;

 

17.第十九步:等待 JVM GC 机制来回收 Student对象; 

 

以上是关于Java中的静态变量&静态方法的主要内容,如果未能解决你的问题,请参考以下文章

java ,为啥无法从静态上下文中引用非静态方法

请教大家关于JAVA中的静态变量和静态方法

Java面试细节:静态变量和静态块静态方法静态类的底层实现原理

java中关于静态变量的问题

java中的静态变量,静态方法与静态代码块详解

Java中的静态和枚举