在总结完 想知道Java代码执行顺序么,Let's go 一文后,对 Java 中的static关键字有了更深的理解,所以有兴趣的可以先看看这篇文章。
前言
Java中没有c、c++这类语言中的全局变量的概念,但是可以通过使用static关键字修饰变量,获得一个类似于全局变量的静态变量。在 Java中,static意为“静态”。可以用来修饰变量、代码块和方法。
static 变量
Java中有两类变量:类变量和实例变量。
*** 类变量: ***被static关键字修饰的变量为类变量、静态变量,JVM 在类的连接阶段,会为类变量赋予默认的初始值,在类初始化阶段,赋予类变量程序中指定的初始化值。类变量伴随着类的产生而产生,类的卸载而消失。所以,在整个类的生命周期中,类变量都只会被初始化一次,并且类变量独立于类的实例而存在,为类的所有实例所共享。
类变量可以直接通过类名来使用,而无需创建该类对象。
*** 实例变量: ***未被static修饰的变量即为实例变量,实例变量与具体的类对象有关,随着对象的实例化而产生,对象的终结而消失。
** 类变量 VS 实例变量 **
- JVM 只会为类变量分配一次内存,而每创建一个实例,JVM 就会为实例变量分配一次内存;
- 类变量的生命周期一般比实例变量长;
- 类变量为类的所有实例所共享,而实例变量只与特定的实例有关;
- 既可以直接使用类名.类变量的方式使用类变量,也可以使用对象.类变量的方式使用类变量,但实例变量只能通过实例访问;
一般会在如下两种情况下使用类变量:在对象之间共享值时和为了方便访问变量时
static块
被static关键字修饰的代码块为静态块,静态块一般用于初始化静态变量,静态块不存在于任何方法体内,可以放在类的任何地方,也可以有多个。当 Java类初始化时,会执行静态块中的代码,静态块和静态域的初始化顺序依程序中定义的顺序而定--** 先定义则先执行 **
static 方法
被static修饰的方法为静态方法。
- 静态方法独立于任何实例,可以直接通过类名引用;
- 静态方法内部不能够引用非静态域和非静态方法,因为静态方法独立于类的实例而存在,而非静态方法/非静态域依赖于类的特定实例,与某一个实例密切相关,当一个类实例对象终结时,与之相关的非静态域和方法也都随之消失,所以如果一个静态方法内部引用了一个非静态域/方法的话,此时就会出错;
- 静态方法内部不能使用 this 和 super 关键字,因为这两个关键字均是与类的实例相关的;
Q & A:
*** Q: ***main 方法为什么设计成static方法?
*** A: ***这是出于效率考虑,将 main 方法设计为 static 的,便可以在类初始化工作完成后就使用该方法,而无需等到创建一个对象后;其次,可以节省内存,因为 static 方法只会占据一份内存,而非 static 的方法则会在每次实例化时均分配内存
*** Q: ***static和final一起使用,会产生什么效果?
*** A: ***static final一般用于表示常量,如果用static final修饰变量,则表示该变量一旦赋值,则不能够再修改它的值(或它指向的对象引用),并且该变量独立于任何实例,可以直接通过类访问;static final 修饰的方法是一个静态的、不能被修改的方法。
示例
public class staticTest {
private static A statica = new A("private static");
public static A staticb = new A("public static");
private static final A STATIC_C = new A("private static final");
public static final A STATIC_D = new A("public static final");
public int a = 8;
static {
print("static block in staticTest");
// a++; 提示 non-static field 'a' cannot be referenced from a static context
}
static void staticMethod(){
print("static method in staticTest");
// a++; 提示 non-static field 'a' cannot be referenced from a static context
}
}
public class staticMain {
public static void main(String[] args) {
staticTest.staticMethod(); // 直接通过类名访问静态方法
print(staticTest.staticb); // 直接通过类名访问静态变量
print(staticTest.STATIC_D);
// staticTest.a; 提示 non-static field 'a' cannot be referenced from a static context
// 非静态方法必须通过实例访问
staticTest test = new staticTest();
print(test.a);
}
}
// Output:
private static
public static
private static final
public static final
static block in staticTest
static method in staticTest
class A & the str is public static
class A & the str is public static final
8