static与JVM
static的特性主要与其在JVM内存中的位置有关。
被static修饰的变量会存放在方法区,被所有线程所共享。(线程共享的区域:堆和方法区,运行时常量也在方法区)
Java内存区域可以分为线程共享内存区(Java堆、方法区)以及线程私有内存区(虚拟机栈、本地方法栈、程序计数器)。线程私有内存区会随线程产生和消亡,因此不需要过多考虑内存回收的问题,编译时需要确定所需内存的大小。
Java堆、方法区、虚拟机栈、本地方法栈在多线程情景下操作不当会抛出OutOfMemoryError,虚拟机栈、本地方法栈在单线程情景下操作不当会抛出StackOutflowError异常。程序计数器不会有内存溢出异常。
JVM中的堆区、方法区、栈区
堆区:
- 存储的都是对象,每个对象都包含与之对应的class信息(class的目的是得到操作指令)
- JVM只有一个堆区被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
栈区:
- 每个线程都包含一个栈区,栈中保存的是基础数据类型的对象和自定义对象的引用(并不是对象本身,对象都放在堆区中了)
- 每个栈中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。
- 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
方法区:
- 又叫静态区,跟堆一样是被所有线程共享的,方法区包含了所有的class和static变量
- 方法区中包含的是在整个程序中永远唯一的元素:如class,static变量
基本用法
基本概念
一句话概括就是:方便在没有创建对象的情况下来进行调用。
被static修饰的,不需要创建对象就能够去调用,形如:类名.调用的对象
static修饰类
一般来说static是用来修饰成员变量或者函数的,修饰类的话指的是一种特殊用法:修饰内部类。普通类不允许被声明位静态的,只有内部类才可以。
static修饰方法
跟修饰类相似,静态方法可以直接通过类名来进行调用。
由于此特性,在静态方法中不能访问类的非静态成员变量和非静态方法,因为非静态成员变量和非静态成员方法必须依赖于具体的对象才能被调用。不过非静态成员变量和非静态成员方法是可以访问静态成员方法和静态成员变量的。
如果想不创建对象的情况下调用某个方法,就可以将这个方法设为static,最常见的就是main方法。程序在执行main方法的时候没有创建任何对象,只有通过类名来访问。
附:static方法是属于类的,非实例对象,在JVM加载类时,就已经存在内存中,不会被虚拟机GC回收掉,这样内存负荷会很大,但是非static方法会在运行完毕后被虚拟机GC掉,以减轻内存压力
static修饰变量
被static修饰的变量,叫做静态变量,也成为类变量,是属于这个类的,而不属于对象。
- 在内存中只有一个副本,在类初次加载的时候才会初始化
- 非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响
- static是不允许用来修饰局部变量。这是Java语法的规定
static修饰代码块
静态代码块在类第一次被载入的时候就会执行。构造方法,用于对象的初始化。而静态代码块,用于类的初始化操作。
在静态初始化块中不能直接访问非staic成员。
作用:提升程序性能,将一些只需要进行一次的初始化操作都放在static代码块中进行。
静态初始化块可以置于类中的任何地方,类中可以有多个静态初始化块。
在类初次被加载时,会按照静态初始化块的顺序来执行每个块,并且只会执行一次。
补充——类的初始化顺序
- 父类静态变量
- 父类静态代码块
- 子类静态变量
- 子类静态代码块
- 父类普通变量
- 父类普通代码块
- 父类构造函数
- 子类普通变量
- 子类普通代码块
- 子类构造函数
小结
特点
- static是一个修饰符,用于修饰成员(成员变量,成员方法),被修饰后的叫做静态变量、静态成员方法
- static修饰的成员被所有的对象共享
- static优先于对象存在,随着类的加载及已经存在
- 可以直接被类名所调用:类名.静态成员
- static修饰的数据是共享数据,对象中存储的是对象特有的数据
成员变量和静态变量的区别
- 生命周期不同
- 成员变量随着对象的创建而存在,随着对象的回收而释放
- 静态变量随着类的加载而存在,随着类的消失而消失
- 调用方式不同
- 成员变量只能被对象调用
- 静态变量可以被对象调用,也可以用类名调用(推荐用类名调用)
- 别名不同
- 成员变量又称实例变量
- 静态变量被称为类变量
- 数据存储位置不同
- 成员变量的数据存储在堆内存的对象中,所以也叫做对象的特有数据
- 静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据
注意事项
- 静态方法之恩呢访问静态成员
- 静态方法中不可以使用this或者super关键字
- 主函数是静态的