Java学习5:static关键字内存分析详解及用法

来源:互联网 发布:万网域名怎么解析 编辑:程序博客网 时间:2024/06/06 03:56

static关键词

1.概述

static关键字可用于修饰变量、方法、初始化块。
分别叫做:静态变量、静态方法、静态初始化块。

1.1静态变量

在类中,用static声明的成员变量为静态变量,或者叫做类属性类变量

特点

  • 静态变量是该类的公共变量,属于类,被该类的所有实例共享,在类被载入时被显示初始化。
  • 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享。
  • 可以使用 对象.类属性 来调用。不过,一般是用 类名.类属性进行调用。
  • static变量置于方法区中

1.2静态方法

用static声明的方法为静态方法;
不需要对象,就可以调用(类名.方法名)。

特点

  • 静态方法是该类的公共方法,属于类,被该类的所有实例共享,在类被载入时被显示初始化。
  • 对于该类的所有对象来说,static方法只有一份。被该类的所有对象共享。
  • 可以使用 对象.类属性 来调用。不过,一般是用 类名.静态方法进行调用。
  • static方法不能访问非静态的方法和属性。

1.3静态初始化块

如果希望加载后,对整个类进行某些初始化操作,可以使用static初始化块
是在类初始化时执行,不是在创建对象时执行。
静态初始化块中不能访问非static成员
执行书序
上溯到Object类,先执行Object的静态初始化块,在向下执行子类的静态初始化块,直到我们的类的静态初始化块位置。

2.static成员内存分析

下面我们从内存分析的角度去理解并解释static成员。

2.1分析代码

首先创建一个Student类及一个Test类。如下:

public class Student {    int age;    String name;    static int staticVar;    public void sayHello() {    }    static void staticMed() {        System.out.println(staticVar);  //静态方法可以访问静态变量    }}
public class Test {    public static void main(String[] args) {        Student.staticVar = 20;        Student stu = new Student();        stu.staticMed();        Student.staticMed();    }}

2.2代码分析

细节的内存分析可参考:图解Java内存分析
这里仅针对static相关进行分析。
1. 当加载类Student时,会在方法区内生成①Student类的代码信息;②static成员;③常量池信息。
这里static的方法并不会再次占用一块内存,而是根据十六进制八位的地址指向类代码信息中的staticMed()方法。
2. Student.staticVar = 20;
直接对方法区的static变量进行复制。
3. Student stu = new Student();
当我们以Student类信息为模板生成stu对象时,并不会生成相应的静态成员(static变量、方法等),仅会生成非静态的,如图中所示,仅有name、age和sayHello()。
4. stu.staticMed();
类的对象可以访问类中的非私有的属性和方法
通过Student类的对象可以调用静态方法和变量,因为静态的属于类,且只有一个,被所有的对象共享。
但如果使用eclipse等IDE,会看到warning的标志,提示我们类方法和类属性应该通过类进行访问。

The static method staticMed() from the type Student should be accessed in a static way

Student.staticMed();
通过类进行方法的调用。

分析图:
这里写图片描述

2.3静态与非静态的调用关系

2.3.1非静态的调用静态的:可以

下面我们在Student类的sayHello()方法中,尝试调用静态成员:staticVar和staticMed();

    public void sayHello() {        System.out.println(staticVar);        staticMed();    }

编译执行通过。
在2.2.4中我们分析,类的对象可以访问类中的非私有的属性和方法,在new Student实例中,虽然没有静态成员staticVar和staticMed(),但是其可以通过访问Student类信息获得。

2.3.2静态的访问非静态的:不可以!

静态方法可以访问静态变量,我们在代码中已经示范了。
下面我们在Student类的staticMed()静态方法中,尝试调用非静态成员:age和sayHello()。

    static void staticMed() {        System.out.println(staticVar);        System.out.println(age);  //报错信息:Cannot make a static reference to the non-static field age        sayHello();               //报错信息:Cannot make a static reference to the non-static method sayHello() from the type Student    }

我们发现会报错,报错信息很简单:static不能指向非static。为什么呢?
我们观察内存图,static成员是在类中,在方法区的static成员中,而非静态的在哪呢?没错,在new Student实例中,在堆空间中,当然访问不到。
另一方面,非静态的属性可以有很多,每生成一个实例就会产生一个age属性,访问时无法确定访问哪一个的。


小结

至此,已经基本分析完,虽然过程比较复杂,但是结论很简单:
静态的从属于类。
静态的只能调用静态的,即从属于类的只能调用从属于类的。
非静态的既可以调用非静态的,又可以调用静态的。

原创粉丝点击