关于Java中的static关键字
Java中的 static 关键字,确实是一个关键的字(key word),今天就来总结一下它的用法,说说为什么关键。
Java中的 static 关键字主要是用来做内存管理的。理解了这句话才能够比较深入地理解static。
static 可以修饰:
- 变量(所谓 class variable)
- 方法(所谓 class method)
- 代码块(所谓 block)
- 内部类(所谓 nested class)
凡是被 static 修饰的这四种元素,都属于class的元素,即类的,而不是类的实例的。
1) 静态变量
在声明变量的时候加上 static ,该变量即是静态变量。
- 什么时候该用 static 来修饰变量呢?该变量被该类的所有实例所共享。
- 静态变量在类被加载的时候初始化,且仅分配一次内存。
这样做的好处就是内存利用率高,看下下面两个demo:
1 // Understanding problem without static variable 2 class Student{ 3 int stuNo; 4 String name; 5 String college="ITS"; 6 }
假设这个"niubility my brother" 的学校有500000000个学生,那么当每一个学生被创建的时候,都会初始化学号、姓名、学校,每个学生都有自己的学号和姓名,这样做没问题;但是每个学生的college字段都相同,如果每次都声明一遍的话,是比较耗内存的。这里的college变量其实是被该类的所有实例所共享的,因此可以将它声明为 static 的。
1 //Program of static variable 2 class Student8{ 3 int rollno; 4 String name; 5 static String college ="ITS"; 6 7 Student8(int r,String n){ 8 rollno = r; 9 name = n; 10 } 11 void display (){System.out.println(rollno+" "+name+" "+college);} 12 13 public static void main(String args[]){ 14 Student8 s1 = new Student8(111,"Karan"); 15 Student8 s2 = new Student8(222,"Aryan"); 16 17 s1.display(); 18 s2.display(); 19 } 20 }
Output:111 Karan ITS
222 Aryan ITS
看下实际内存分配情况:
静态变量分配在了方法区,堆中该类的所有实例共享方法区中的college。
再看一下下面这个栗子:Counter 类中声明了一个count变量,在构造函数中对其进行++操作,因为实例变量在对象被创建的时候分配内存,所有每一个对象都有一份自己的count副本,每个对象对各自count的++操作不会反应到其他对象上。
1 class Counter{ 2 int count=0;//will get memory when instance is created 3 4 Counter(){ 5 count++; 6 System.out.println(count); 7 } 8 9 public static void main(String args[]){ 10 11 Counter c1=new Counter(); 12 Counter c2=new Counter(); 13 Counter c3=new Counter(); 14 15 } 16 }
Output:1 1 1
因为静态变量仅仅在类加载的时候分配一次内存,所以如果将count修饰为static,那么该类的所有对象将会共享该变量,每一个对象对count的操作都会反应到其他对象上。
1 class Counter2{ 2 static int count=0;//will get memory only once and retain its value 3 4 Counter2(){ 5 count++; 6 System.out.println(count); 7 } 8 9 public static void main(String args[]){ 10 11 Counter2 c1=new Counter2(); 12 Counter2 c2=new Counter2(); 13 Counter2 c3=new Counter2(); 14 15 } 16 }
Output:1 2 3
2)静态方法
在声明方法的时候加上 static 关键字,即静态方法:
- 静态方法属于类而不是对象。
- 静态方法可以直接通过类名调用,而不需要创建类的对象。
- 静态方法可以修改静态变量,而非静态方法不可以。
一个静态方法的栗子:
1 //Program of changing the common property of all objects(static field). 2 class Student9{ 3 int rollno; 4 String name; 5 static String college = "ITS"; 6 7 static void change(){ 8 college = "BBDIT"; 9 } 10 11 Student9(int r, String n){ 12 rollno = r; 13 name = n; 14 } 15 16 void display (){System.out.println(rollno+" "+name+" "+college);} 17 18 public static void main(String args[]){ 19 Student9.change(); 20 21 Student9 s1 = new Student9 (111,"Karan"); 22 Student9 s2 = new Student9 (222,"Aryan"); 23 Student9 s3 = new Student9 (333,"Sonoo"); 24 25 s1.display(); 26 s2.display(); 27 s3.display(); 28 } 29 }
Output:111 Karan BBDIT 222 Aryan BBDIT 333 Sonoo BBDIT
静态方法的第二颗栗子:
1 //Program to get cube of a given number by static method 2 class Calculate{ 3 static int cube(int x){ 4 return x*x*x; 5 } 6 7 public static void main(String args[]){ 8 int result=Calculate.cube(5); 9 System.out.println(result); 10 } 11 }
静态方法的两个注意点:
- 静态方法不能操作非静态变量,也不能调用非静态方法。(这个可以这样理解:静态方法属于类,直接通过类名就可以调用,而此时可能没有任何实例,更谈不上操作实例变量和调用实例方法了。)
- 静态方法中不能使用 this 和 super 关键字。(道理同上)
1 class A{ 2 int a=40;//non static 3 4 public static void main(String args[]){ 5 System.out.println(a); 6 } 7 }
Output:Compile Time Error
Q)为什么Java的main方法是static的?
Ans)为了使得在调用main方法之前不需要创建任何实例对象。
3)静态代码块
为什么要有这个东西?干嘛用呢?
- 用来初始化静态变量。
- 在类加载时,在执行main方法之前执行相关操作。
栗子:
1 class A2{ 2 static{System.out.println("static block is invoked");} 3 public static void main(String args[]){ 4 System.out.println("Hello main"); 5 } 6 }
Output:static block is invoked Hello main
Q)没有main方法的程序可以执行吗?
Ans)可以,在JDK1.7之前执行如下代码是可以的:
1 class A3{ 2 static{ 3 System.out.println("static block is invoked"); 4 System.exit(0); 5 } 6 }
Output:static block is invoked (if not JDK7)
但是在JDK1.7会报如下错误:
Output:Error: Main method not found in class A3, please define the main method as: public static void main(String[] args)
4)静态内部类
被static修饰的类,并且处于某个类的内部。
- 它可以访问外部类的静态成员,包括private成员。
- 它不能访问外部类的非静态成员。(原因前面说过)
那么为什么要有静态内部类呢?看下面的栗子:
1 class TestOuter1{ 2 static int data=30; 3 static class Inner{ 4 void msg(){System.out.println("data is "+data);} 5 } 6 public static void main(String args[]){ 7 TestOuter1.Inner obj=new TestOuter1.Inner(); 8 obj.msg(); 9 } 10 }
Output:data is 30
main方法中创建了一个静态内部类的实例,并且调用了其msg() 方法。但是这里并没有创建外部类的实例,因为这里的Inner类是static的,并且可以访问外围类的static成员。如果把Inner之前的static去掉,那么这里要这样写:
TestStaticInnerClass.Inner obj=new TestStaticInnerClass().new Inner();
需要先创建外一个部类实例,然后才能创建内部类实例。静态内部类不仅高效利用内存,而且使得代码简洁。下面是static 内部类编译后的样子:
1 // Internal class generated by the compiler 2 import java.io.PrintStream; 3 static class TestOuter1$Inner 4 { 5 TestOuter1$Inner(){} 6 void msg(){ 7 System.out.println((new StringBuilder()).append("data is ") 8 .append(TestOuter1.data).toString()); 9 } 10 }
上例中,如果msg() 方法也是静态的,那么内部类的实例也不需要创建了:
1 class TestOuter2{ 2 static int data=30; 3 static class Inner{ 4 static void msg(){System.out.println("data is "+data);} 5 } 6 public static void main(String args[]){ 7 TestOuter2.Inner.msg();//no need to create the instance of static nested class 8 } 9 }
Output:data is 30
以上是关于Java 中 static 关键字的理解,参考了:http://www.javatpoint.com/