美文网首页
Java关键字之static

Java关键字之static

作者: l1fe1 | 来源:发表于2020-05-10 23:20 被阅读0次

1 前言

static意思是静态的、全局的,在java中一旦被static修饰,说明被修饰的东西在一定范围内是共享的,谁都可以访问,这时候需要注意并发读写时的线程安全问题。被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问,这使得我们可以很方便的在没有创建对象的情况下来进行方法/变量的调用/访问。

2 修饰的对象

static 可以用来修饰变量、方法、内部类和代码块。

2.1 静态变量

使用 static 修饰的变量是属于类的,而不是属于对象的,静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。
注意,static 关键字并不能修改变量的访问权限,也就是说 private 变量即使使用 static 关键字修饰,依然只能由本类及本类的对象访问,而用 static 关键字修饰的 public 变量可以被任何类直接访问,而无需初始化类,直接使用 类名.static变量 这种形式访问即可。
在使用多个线程对静态变量进行读写时,需要注意它的线程安全问题,比如对于public static List<String> list = new ArrayList();这样的共享变量在并发环境下进行读写时就会产生线程安全问题,这时我们可以使用线程安全的 CopyOnWriteArrayList 或者在读写时手动进行加锁来保证多线程读写下的线程安全。
静态变量在字节码层面是使用访问标志位来进行标识的,如下图所示:

static变量的访问标志位
也就是说,在类加载时,JVM会通过class文件中的访问标志位来判断某个变量是否为静态变量。

2.2 静态方法

和静态变量一样,静态方法也可以不依赖于任何对象就直接进行访问,因此对于静态方法来说,是没有 this 的,因为它不依附于任何对象,而 this 本身就是个对象。由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用/访问的,而反过来,非静态成员方法是可以调用/访问静态成员方法/变量的。
static 方法内部的变量在执行时是没有线程安全问题的。方法执行时,数据运行在栈里面,栈里面的数据每个线程都是隔离开的,所以不会有线程安全的问题。
static 方法在字节码层面是使用一个ACC_STATIC的标志位来进行标识的,如下图所示:


static方法的标志位

2.3 静态内部类

普通类是不允许声明为静态的,只有内部类才可以,使用 static 修饰的内部类可以直接由外部类来创建和访问,而没有用 static 修饰的内部类则必须要先实例化一个外部类的对象,再通过外部类的对象来创建内部类的实例。

2.4 静态代码块

static 关键字还可以修饰代码块用于在类启动之前,初始化一些值。static 块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。在静态代码块中只能调用同样被 static 修饰的变量,并且 static 的变量需要写在静态块的前面,不然编译会报错。
和 static 方法一样,静态代码块在字节码层面使用一个ACC_STATIC的标志位来进行标识。

3 初始化时机

我们通过一个演示程序来测试一下被 static 修饰的类变量、代码块和方法的初始化时机:

public class Parent {

    private static List<String> parentList = new ArrayList(){{
        System.out.println("父类静态变量初始化");
    }};

    static {
        System.out.println("父类静态代码块初始化");
    }

    public Parent() {
        System.out.println("父类构造器初始化");
    }

    public static void testStatic() {
        System.out.println("父类静态方法被调用");
    }

}
public class Child extends Parent {

    static {
        System.out.println("子类静态代码块初始化");
    }

    private static List<String> childList = new ArrayList(){{
        System.out.println("子类静态变量初始化");
    }};

    public Child() {
        System.out.println("子类构造器初始化");
    }

    public static void main(String[] args) {
        System.out.println(" main 方法执行");
        new Child();
    }

}

运行程序,发现打印的结果是:

父类静态变量初始化
父类静态代码块初始化
子类静态代码块初始化
子类静态变量初始化
 main 方法执行
父类构造器初始化
子类构造器初始化

因此,我们可以得出以下结论:

  1. 父类的静态变量和静态代码块比子类优先初始化;
  2. 静态变量和静态块比类构造器优先初始化;
  3. 静态变量和静态代码块按照定义的顺序依次进行初始化;
  4. 被 static 修饰的方法,在类初始化的时候并不会执行,只有当自己被调用时,才会被执行。

4 面试题

如何证明 static 静态变量和类无关?

  1. 不需要初始化类就可直接使用静态变量;
  2. 在类中写个 main 方法运行,即便不写初始化类的代码,静态变量都会自动初始化;
  3. 静态变量只会初始化一次,初始化完成之后,不管再 new 多少个类出来,静态变量都不会再初始化了。

相关文章

  • Java static关键字

    Java之美[从菜鸟到高手演变]之Java中static关键字

  • Java基础系列-static关键字

    原创文章,转载请标注出处:《Java基础系列-static关键字》 一、概述 static关键字是Java诸多关键...

  • Static关键字

    C语言中的static关键字和Java的static关键字意义不一样。 1 用static修饰函数 static用...

  • Java 面向对象2

    Java 面向对象 1. static 和 final static关键字---修饰成员变量 用static修饰的...

  • 1.3 static 关键字

    static 关键字 《Java编程思想》 中:static方法就是没有this的方法 static 修饰的方法或...

  • Java static关键字

    声明static属性 static是Java中定义的一个关键字,主要是描述全局的概念,所以利用static关键字可...

  • 代码查错

    Something1.java 5。 static关键字 static修饰成员变量 用static修饰的成员变量不...

  • Java:3分钟带你全面了解Static静态关键字

    前言 在Java中,静态 Static关键字使用十分常见 本文全面 & 详细解析静态 Static关键字,希望你们...

  • java面试问题总结与分享,很乱

    java中static关键字的作用 在Java中static表示“全局”或者“静态”的意思,用来修饰成员变量和成员...

  • java关键字之static

    static学习笔记 static表示“全局”或者“静态”的意思,用来修饰成员变量或者是成员方法,也可以形成静态的...

网友评论

      本文标题:Java关键字之static

      本文链接:https://www.haomeiwen.com/subject/pnvsnhtx.html