转载自大佬:https://www.cnblogs.com/xrq730/p/4820992.html
静态资源和静态方法
首先,静态的资源和方法等会随着类的加载而进入内存被初始化,而非静态的资源和方法会随着new的动作被初始化。即,静态先,非静态后。
由于这种特性,我们可以理解static的基本用法:
1、被static修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要new出一个类来
2、被static修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要new出一个类来
被static所修饰的变量是唯一的静态资源,是各个对象实例化后所共享的资源,则静态资源被改变后,所有实例中的该资源都会改变。
下面来理解一个问题:静态方法能不能调用非静态资源?以下面代码为例
public class A { private int i = 1; public static void main(String[] args) { i = 1; } }
main方法是静态方法,i是非静态资源。在类加载进入内存时,main方法初始化,方法中的所有资源都要被加载进内存。而由于i是非静态资源,要通过new来初始化,所以i并不能进入内存。
所以我们可以得到以下结论:
1,静态方法不能调用非静态资源
2,静态方法可以调用静态资源
3,非静态方法可以调用静态资源
静态代码块
静态块的语法如下
static{ statments; ........ }
静态块是用于初始化一个类的时候同时进行一些操作的。静态块中的代码只在初始化类的时候执行一次。
public class A { private static int a = B(); static { System.out.println("Enter A.static block"); } public static void main(String[] args) { new A(); } public static int B() { System.out.println("Enter A.B()"); return 1; } }
打印结果:
Enter A.B() Enter A.static block
我们看到,在main方法中,首先new了对象A,按顺序加载a=B(),调用方法B,打印Enter A.B(); 然后打印静态块中的内容。
可以得到结论:静态资源的加载顺序是严格按照静态资源的定义顺序来加载的
再看一个例子:
1 public class A 2 { 3 static 4 { 5 c = 3; 6 System.out.println(c); 7 } 8 9 private static int c; 10 }
这段代码的第6行是有错误的“Cannot reference a field before it is defined”。从这个例子得出第二个结论:静态代码块对于定义在它之后的静态变量,可以赋值,但是不能访问。
最后一个小例子:
1 public class A 2 { 3 static 4 { 5 System.out.println("A.static block"); 6 } 7 8 public A() 9 { 10 System.out.println("A.constructor()"); 11 } 12 }
1 public class B extends A 2 { 3 static 4 { 5 System.out.println("B.static block"); 6 } 7 8 public B() 9 { 10 System.out.println("B.constructor()"); 11 } 12 13 public static void main(String[] args) 14 { 15 new B(); 16 new B(); 17 } 18 }
结果是
A.static block B.static block A.constructor() B.constructor() A.constructor() B.constructor()
这个例子得出第三个结论:静态代码块是严格按照父类静态代码块->子类静态代码块的顺序加载的,且只加载一次。
static修饰类
这个用得相对比前面的用法少多了,static一般情况下来说是不可以修饰类的,如果static要修饰一个类,说明这个类是一个静态内部类(注意static只能修饰一个内部类),也就是匿名内部类。像线程池ThreadPoolExecutor中的四种拒绝机制CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy就是静态内部类。静态内部类相关内容会在写内部类的时候专门讲到。 待补充
import static
这个比较冷门,基本很少看见有地方用,使用JUnit可能会用到,写assert的时候会方便些。import static是JDK1.5之后的新特性,这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名.资源名,可以直接使用资源名。注意一下,import static必须这么写,而不能写成static import。举个例子来看一下:
package chapter3Demos; import static java.lang.System.out; import static java.lang.Math.*; public class Demo3_3_2 { public static void main(String[] args) { out.println(sin(2.2)); } }
第一个import static表示直接指定导入out这个静态资源,可以省略写System,但是不能使用其他System类中的静态方法。
第二个import static表示导入了Math类中所有的静态方法,不仅sin可以不写Math,其他数学函数也可以省略不写
这种写法减少了代码量,简化了一些操作,但是降低了代码的可读性。
除了在一些特定场合用到之外,建议不要使用。