Java之static关键字

180 阅读4分钟

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");
    }
}

答案是

恭喜你写对啦!!