static关键字
在Java类中,可用static修饰属性、方法、代码块、内部类。
被static修饰的成员有以下特点:
- 随着类的加载而加载。
- 优先于对象存在。
- 修饰的成员,被所有对象所共享。
- 访问权限允许时,可不创建对象,直接被类调用。
静态变量
使用static修饰的变量是属于类的,而不是属于对象,静态变量被所有的对象所共享,在内存中只有一个副本,它只在类初次加载时会初始化。
静态变量有两种引用方式:类名.静态变量、对象.静态变量。
静态变量在字节码层面使用访问标志位(Access Flags)来进行标识。可以通过使用 Java 反编译工具来查看字节码文件。
注意:static并不能修改变量的访问权限。
静态变量与其他变量的区别
| 成员变量 | 局部变量 | 静态变量 | |
|---|---|---|---|
| 定义位置 | 方法外,类内部定义 | 方法内、方法参数、代码块内部定义 | 方法外,类内部定义,由static修饰的成员变量 |
| 初始化值 | 有默认初始化值 | 没有初始值,必须赋值才可以使用 | 有默认初始化值 |
| 调用方式 | 对象调用 | 通过变量名 | 对象调用,类名调用 |
| 存储位置 | 堆中 | 栈中 | 方法区的静态域 |
| 生命周期 | 与对象共存亡 | 与方法共存亡 | 与类共存亡 |
如何确定一个属性是否要声明为static?
前提是该属性可以被多个对象所共享的,不会随着对象的不同而不同。这时候可以用static修饰此属性。类中的常量也常常声明为static。
静态方法
与变量相似,java同时提供了静态方法(类方法)和非静态方法。
引用方式:类名.方法名
在静态方法中不能访问类的非静态成员变量和非静态方法,静态方法随着类的加载而加载,类加载的时候还没有对象。非静态方法/成员变量都是必须依赖具体的对象才能够被调用。反过来,非静态方法是可以调用静态方法/成员变量的。
注:静态方法中不能使用this和super关键字,static修饰的方法不能被重写。
static 方法在字节码层面是使用一个ACC_STATIC的标志位来进行标识的。
如何确定一个方法是否声明为static
操作静态属性的方法,通常设置为static。 工具类中的方法,习惯上声明为static。比如Math、Arrays。
静态内部类
普通类是不允许声明为静态的,只有内部类才可以,使用 static 修饰的内部类可以直接由外部类来创建和访问,而没有用 static 修饰的内部类则必须要先实例化一个外部类的对象,再通过外部类的对象来创建内部类的实例。
静态代码块
静态代码块用于在类启动之前,初始化一些值。静态代码块可以置于类中的任何地方,不能存在于任何方法体内。在类初次被加载的时候,会按照静态代码块的顺序来执行每个静态代码块,并且只会执行一次。
静态代码块经常被用来初始化静态变量。
和静态方法一样,静态代码块在字节码层面使用一个ACC_STATIC的标志位来进行标识。
初始化顺序
代码块分为以下三种:
- 静态代码块:定义在类中,用static修饰的代码块。
- 构造代码块:定义在类中,没有任何修饰符。
- 普通代码块:定义在方法或语句中出现的{}就称为普通代码块。
其中,静态代码块只执行一次,构造代码块在每次创建对象时都会执行,普通代码块和一般的语句执行顺序一样。
静态变量/静态代码块>main方法>成员变量/构造代码块>构造函数>普通代码块
来试试做题
public class JavaTest {
public static void main(String[] args) {
new MyTest();
}
}
class Person{
static {
System.out.println("Person static");
}
public Person(String str){
System.out.println("person"+str);
}
}
class Test{
Person person=new Person("Test");
static {
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
}
class MyTest extends Test{
Person person=new Person("MyTest");
static {
System.out.println("MyTest static");
}
public MyTest(){
System.out.println("MyTest constructor");
}
}
答案是
恭喜你写对啦!!