static 关键字

static 关键字

概述

  static 是 Java 中的一个关键字,它可用于定义成员变量、方法、代码块和内部类,下面来分别讲述该关键字用于不同的目标上的作用。

static 成员变量

  使用 static 定义的成员变量叫做静态成员变量,它与一般的成员变量不同,普通成员需要依赖与具体的对象实例,而静态成员只依赖特定类对象(类也是对象,但全局只有一个),我们可以直接通过类来访问该静态成员,也可以通过对象实例来访问(但一般不建议,对于类成员,最好都是通过类来访问)

public class Static {
    private static int number = 0;

    public static void main(String[] args) {
        // 直接通过类引用静态成员
        Static.number++;
        System.out.println("number 的值为"  + Static.number);

        // 创建实例
        Static s1 = new Static();
        s1.number++;
        System.out.println("number 的值为"  + Static.number);
    }
}

结果:
number 的值为1
number 的值为2

  从上述测试代码可以知道,对静态成员的修改是会影响具体的值,因为静态成员是全局的。

static 方法

  static 静态方法和静态成员类似,它都是依赖于类,而不依赖于具体的对象实例,在 static 方法中,不可以使用本类中非静态的成员或方法,因为这些成员需要依赖于具体的类,在静态方法调用过程中,并没有具体的对象实例被创建,因此使用它们是非法的。
  另外,static 方法不可被重写,方法重写是利用多态动态绑定来实现子类对象行为替换父类对象行为,static 方法是类方法,是一种静态绑定,在编译期已经确定了调用行为,因此 static 方法不可被重写。

static 代码块

  static 代码块是在类第一次加载的时候被调用的,且只会调用一次,常用于初始化一些系统参数操作。
  下面通过例子来说明一个当一个子类对象创建,它的初始化的顺序是怎么样的

public class Static {
    public static void main(String[] args) {
        Parent parent = new Child();
    }

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

    public Parent() {
        System.out.println("父类构造器调用中");
    }

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

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

    public Child() {
        System.out.println("子类构造器调用中");
    }

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

输出结果:
父类 静态代码块初始化
子类静态代码块初始化
父类代码块初始化
父类构造器调用中
子类代码块初始化
子类构造器调用中

  从例子可以看出,new 一个对象,若此时对应的类还为加载,则其创建顺序是:
1. 按继承层次从高到低,依次加载各个父类,最后加载子类,按照定义的先后顺序初始化静态成员和执行静态代码块,
3. 按继承层次,按照定义的先后顺序初始化普通成员和执行普通代码块,
4. 按继承层次,依次调用类的构造方法

  销毁对象时,则从低到高依次销毁,先回收子类,再回收父类。

static 内部类

  static 不可以用于定义普通类,只能用于定义内部类,普通内部类需要依赖于外部类对象,而静态内部类它不需要依赖于外部类对象的存在。
  对于静态内部类的使用,下面介绍一种用于解决单例模式(懒汉型)在多线程并发不安全的问题:

首先,采用 DCL 方式的单例模式(懒汉型)的实现代码:

class LazySingleton {
    private volatile static LazySingleton instance = null;

    private LazySingleton() { }

    public static LazySingleton getInstance() {
        //第一重判断
        if (instance == null) {
            //锁定代码块
            synchronized (LazySingleton.class) {
                //第二重判断
                if (instance == null) {
                    instance = new LazySingleton(); //创建单例实例
                }
            }
        }
        return instance;
    }
}

  从上述代码看,在 Java 1.5 后该代码是没有问题,因为 LazySingleton 使用 volatile 关键字来定义,因为 volatile 关键字保证了每次读写某个变量时都需要从主内存中重新读取最新的值到工作内存中,这样保证了线程能够看到其他线程的更新,但采用 volatile 变量,它本身会禁止编译器对齐进行的优化,所以可能会导致使用性能下降,下面采用静态内部类来更好的实现懒汉型单例模式(关于 volatile 变量 可以去了解 JMM 以及 volatile 变量的规则)

class Singleton {  
    private Singleton() {  
    }  

    private static class HolderClass {  
            private final static Singleton instance = new Singleton();  
    }  

    public static Singleton getInstance() {  
        return HolderClass.instance;  
    } 
}

 该方式在第一次创建单例类实例时,会先加载静态内部类,并且加载过程中会创建单例类,该过程由 JVM 来保证线程安全,不需要使用 volatile 变量。这种方式既能实现延迟加载,也可以保证线程安全,同时还不影响系统性能,是实现单例模式的一种好方法。

总结

  对于 static 关键字,它可用于定义成员、方法、代码块和内部类,静态成员和静态方法都依赖于类,不依赖与具体的对象实例,并且对静态成员的修改是全局影响的,另外静态方法采用静态绑定,它不可被重写。
  定义静态代码块,它在在类被加载的时候会被调用,并且只调用一次,常用于初始化一些与类相关的参数信息。静态内部类不需要依赖于外部类对象的存在,并且它可用于实现单例模式,提供一种较优的方式。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值