概述
static 在java体系里的地位:java语言的一个修饰符,属于非访问修饰符,所谓访问修饰符就是控制访问权限的修饰符,如public,protected,private,default
再来看看static翻译成中文的意思:静止的; 静电的; 不变的; [物] 静力的。显而易见,在程序设计语言中最准确的意思应该取的意思是 静止的,不变的较为准确.
一般来说,当创建类时,就是在描述那个类的的对象的外观和行为,除非用new创建那个类的对象,否则,实际上并未获得任何对象。执行new来创建对象时,数据存储空间才被分配,其方法才供外界调用。但两种情形是以上方法无法解决的。
一种是只想为某特定域分配单一存储空间,而不去考虑究竟要创建什么对象,甚至根本就不创建任何对象。
另一种是希望某个方法不与包含它的类的任何对象关联在一起。也就是说,即使没有创建对象,也能调用这个方法
Static关键字就是为了满足这两方面的需要。
当声明一个事物(注意:是一个事物,一个方法一个变量都是一个事物),当声明一个事物是static时,就意味着这个域或方法不会与包含它的那个类的任何对象事例关联在一起。所以,即使从未创建某类的任何对象,也可以调用其static方法或者访问其static域。static关键字的用途简言之就是方便在没有创建任何对象的前提下,仅仅通过类本身来调用static方法/变量。static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
static方法和字段的一个重要用法就是在不创建任何对象的前提下就可以调用它。这一点对main方法很重要,main 方法是我们的应用程序入口。
静态变量存储在metaspace,即以前的方法区。
static关键字主要的用法有如下几种
修饰类的变量
用static修饰的变量
(1) 用static关键字修饰的变量成为静态变量.
(2)用static修饰的变量属于一个类,他在jvm内存中的分配区域是一块不变区域,可以称之为静态存储区
(3)静态变量的加载是在类加载时完成初始化的。它在内存中只有一份, 一般在对象中共享数据时才定义static的变量。
此外,static变量是属于类的,不属于类的某一个对象,static变量存放的区域叫做:PermGem Sections,而我们知道对象是存放在堆(heap)上的。
没有用static关键字修饰的变量称为实例变量,用static修饰的是类变量
(1)实例变量是伴随着一个实例,一个对象的,他的生命周期与该对象一致。
(2)实例变量在内存中分配给每一个对象,每一个实例变量都是属于一个对象的。
修饰方法
类的静态成员(变量和方法)属于类本身(注意是类本身,不是某一个对象),在类加载的时候就会分配内存,可以通过类名直接去访问. static修饰的方法是属于类的一个方法,不需要创建对象就可以调用。
非static方法只能在对象被创建之后才能调用。
static只能直接调用类的static方法,不能直接调用非static方法,若要调用非static方法,需要new相应的类的实例,再通过他来调用。 原因在于:
程序最终都将在内存中执行,变量只有在内存中占有一席之地时才能被访问。
类的静态成员(变量和方法)属于类本身,在类加载的时候就会分配内存,可以通过类名直接去访问;非静态成员(变量和方法)属于类的对象,所以只有在类的对象产生(创建类的实例)时才会分配内存,然后通过类的对象(实例)去访问。
详细参考:https://www.cnblogs.com/wxw7blog/p/7053212.html
修饰代码块
static代码块是独立于成员变量和成员函数的代码块。只会在JVM加载类时会执行这些静态的代码块,且只被执行一次。
静态导入包
采用static导入包后,在不与当前类的方法名冲突的情况下,无需使用“类名.方法名”的方法去调用类方法了,直接可以采用"方法名"去调用类方法,就和调用类自己的方法一样
用法
对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。至于是否要触发子类的加载和验证,在虚拟机中并未明确规定,这取决于虚拟机的具体实现。例如:
public class SuperClass {
static {
System.out.println("SupperClass init");
}
public static int value = 123;
}
public class NoInitialization {
public static void main(String[] args){
System.out.println(SubClass.value);
//对于静态字段,只有直接定义这个字段的类才会被初始化
}
}
public class SubClass extends SuperClass {
static {
System.out.println("SupperClass init");
}
}
上面这个程序的输出结果如下:
SupperClass init
123
但是这儿有个问题,根据static代码块的定义,在类加载时,static代码块会被执行一次,那么这里子类难道没有被虚拟机加载吗?事实上这取决于虚拟机的实现,在sun HotSpot虚拟机中,可以通过-XX:+TraceClassLoading参数观察到此操作会导致子类的加载。
static关键字与java内存
从java虚拟机的的内存角度分析,static修饰的变量存储于方法区,而不是一般字段的堆内存。这意味着,static变量并不存在生命周期一说。并且其垃圾收集和普通对象的垃圾收集也是不一样的。