static关键字分析

static关键字

一种表示静态属性的修饰符。用于为特定区域分配单一存储空间,不考虑要创建多少对象或者说根本就不创建任何对象,再就是想在没有创建对象的情况下也去调用方法

static关键字作用

  • 用来修饰类的成员
    • 修饰成员变量——静态变量
    • 修饰成员方法——静态方法
  • 当类被加载时,会优先被加载
  • 用来修饰代码块——静态代码块,先于类的构造方法之前执行且只会执行一次。用来对静态成员做初始化
  • 静态修饰的成员被所有的对象共享
  • 调用静态方法或对象时,可以直接通过类名.成员方法/变量来进行访问

能实现上述作用的原理在于:

  1. 代码都是在编译时 由系统分配内存
  2. 静态变量编译时,所分配的内存会一直存在,直到程序退出时才会被释放
  3. 类加载时,静态变量会被放到方法区中,被所有的对象实例共用

static关键字用法

修饰类——静态类

静态类又名静态内部类该类独立存在,形式上与外部类有内外关系,实际上没有任何关联,本质是为了 隐藏自身。可不依赖外部类进行实例化,只能访问外部类的静态成员变量及成员方法。

内部类:定义在类中的另外一个类。隐藏在外部类中且封装性更强,不允许除外部类外的其他类对其进行访问。但可以直接访问到外部类的成员。

成员内部类:可以直接使用外部类的所有成员和方法,即时是private修饰的。

局部内部类:内部类定义在方法内,只能在该方法或条件的作用域才能使用,退出这作用域就无法引用。

匿名内部类:只能使用一次,通过用来简化代码编写,还有个前提条件:必须继承一个父类或实现一个接口。

1
2
3
4
5
6
7
8
9
10
public class A{
//静态内部类
public static class B{

}
//普通内部类
public class C{

}
}

修饰代码块——静态代码块

静态代码块用于初始化一个类的时候做操作用的,和静态变量、静态方法一样会随着类的加载一块执行,而且可以随意摆放位置。对应类加载过程的最后一步:类初始化(执行<clinit>方法)

1
2
3
4
5
6
7
public class Test{
static int i = 1;
static {
//最终得到 为0
i = 0;
}
}

若存在多个 static代码块,JVM按照他们出现的先后顺序依次执行。静态代码块只能访问定义在它之前的变量,定义在其后的是不能访问的。

修饰方法——静态方法

使用static修饰成员方法。通过ClassName.methodName()直接访问,由于它在类加载时就存在了,不依赖于任何实例。

1
2
3
4
5
6
public class Test{
//静态方法
public static void main(String[] args){

}
}

只能访问所属类的静态成员变量和静态方法,不能使用this、super关键字

修饰变量——静态变量

使用static修饰变量。通过ClassName.propertyName直接访问静态变量。

静态变量是 随着类加载时完成初始化的,在内存中仅有一份,且只分配一次内存。同时被所有的实例共享静态变量。

实例变量:每创建一个实例,JVM就会为实例变量分配一次内存,它与创建它的实例同生共死。

1
2
3
4
5
public class Test{
private static int a = 0;//静态变量
}

可通过Test.a直接访问

一般在这两种情况下使用静态变量对象之间共享数据以及访问数据。

static关键字注意事项

  • 静态方法不能被覆盖,方法覆盖是动态绑定的,静态方法时在编译时静态绑定的。
  • 在静态方法、静态类中无法访问非static变量、方法
  • 静态方法可以引用静态的变量或方法,由于 *静态的这些都是在类加载时就加载好,都是可以互相调用到的。
  • 非静态方法中也可以引用静态的变量或方法。

static关键字使用实例

单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton{
private static class SingletonHolder{
private static final Singletion INSTANCE = new Singleton();
}

private Singleton(){

}

public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}

为何可以保证线程安全?虚拟机可以保证一个类的类构造器()`在多线程环境中被正确的加锁、同步。如果多个线程同时去初始化一个类,只有一个线程可以去执行类构造方法,其他线程都会阻塞等待,直到构造方法执行完毕。同一个类加载器下,一个类型只会被初始化一次。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!