static是Java中的一个关键字,用来修饰成员变量与成员方法,还可以用于编写静态代码块,对于被static修饰的东西,JVM在加载类的时候,就给这些变量在内存中分配了一定的空间,即在编译阶段时就为这些成员变量的实例分配了空间。
一、静态变量
被static关键字修饰的成员变量叫做静态变量,前面我们讲到成员变量与局部变量的区别,那么静态变量与成员变量又有哪些不同呢?
1、调用方式
静态变量:类变量,可以直接通过类名调用,也可以通过对象名调用,这个变量属于类
成员变量:实例变量,只能通过对象名调用,这个变量属于对象
2、存储位置
静态变量:存储在方法区中的静态区
成员变量:存储在堆内存
3、生命周期
静态变量:随着类的加载而存在,随着类的消失而消失
成员变量:随着对象的创建而存在,随着对象的消失而消失
4、与对象的相关性
静态变量:所有对象共享的数据,在内存中只有一个副本
成员变量:每个对象所特有的数据,在内存中存在多个副本,每个副本之间互不影响
看了以上几点,我们会想那什么时候使用static来修饰我们的变量呢,从第4点可以看出当所定义的变量是所有的实例所共享的数据的时候,我们就可以用static来修饰,例如,我们每个人都有国籍,通常情况下国籍都是中国,那么这个时候就可以用static来修饰了
1 package demo; 2 3 public class Person { 4 private String name; 5 private int age; 6 private static String nationality = "中国"; 7 8 .... 9 }
这样当构造Person类的时候就不用每次都给nationality这个属性分配内存空间,这时在内存中就只有一个副本,每个实例对象都指向它,当其中一个改变了nationality变量的值,则其他对象的nationality值也随着改变。
二、静态方法
被static关键字修饰的成员方法叫做静态方法,看看我们最常见的main方法
1 package demo; 2 3 public class MainDemo { 4 public static void main(String[] args) { 5 System.out.println("main method"); 6 } 7 }
此时代码中并没有构造一个MainDemo对象,但是运行程序却在控制台打印出了main method,这个例子可以说明静态方法优于对象而存在,与静态变量一样,在类加载时就存在了,如果我们在静态方法中调用非静态变量与非静态方法会有什么现象呢,看下面这段代码
1 package demo; 2 3 public class MainDemo { 4 private String name; 5 private static String address; 6 7 public static void main(String[] args) { 8 show1(); // Cannot make a static reference to the non-static method 9 // show1() from the type MainDemo 10 show2(); 11 } 12 13 private void show1() { 14 System.out.println(name); 15 System.out.println(address); 16 } 17 18 private static void show2() { 19 System.out.println(name); // Cannot make a static reference to the 20 // non-static field name 21 System.out.println(address); 22 } 23 }
代码中第8行与第19行报错,报错信息在代码右侧已经注释出来,由于静态方法在类加载的时候就已经在内存中了,此时对象还不存在,故在静态方法中无法访问非静态变量,非静态变量在创建对象的时候才会在堆空间中存在,一个不存在的东西又怎么能访问呢,同样在静态方法中无法访问非静态方法的原因与之一样。
既然非静态方法为所有实例所共享,那么该方法也为类所有,那自然可以通过类名调用
1 package demo; 2 3 public class MainDemo { 4 private static String address; 5 6 public static void main(String[] args) { 7 MainDemo.show(); 8 } 9 10 private static void show() { 11 System.out.println(address); 12 } 13 }
三、静态代码块
static块可以置于类中的任何地方,类中可以有多个static块。与成员变量,成员方法一样,在类被加载的时候静态代码块就存在于内存中了,在类初次加载的时候,JVM按照static块的顺序来执行每个static块,并且只会执行一次,这样无形中也提高了点性能。
1 package demo; 2 3 public class StaticDemo { 4 private static String address = "china"; 5 6 static { 7 System.out.println("first static block"); 8 } 9 10 static { 11 System.out.println("second static block"); 12 } 13 14 public static void main(String[] args) { 15 StaticDemo.show(); 16 } 17 18 private static void show() { 19 System.out.println(address); 20 } 21 }
输出结果:
first static block second static block china
从以上我们总结出以下static关键字的一些特性:
1、可以用来修饰成员变量,成员方法,静态代码块;
2、随着类的加载而加载,优先于对象而存在,被所有的对象所共享,可以被类名直接调用(建议),当然也通过实例调用,虽然在内存中的副本只有一个,不过生命周期长,当类被回收时,静态区域空间才会被释放;
3、静态方法中只能访问静态变量与静态成员;
4、当所有对象共享某个数据的时候,就把这个成员变量定义为静态的;
5、静态代码块只执行一次。