static有多种用法,它静态变量、静态方法、静态代码块、静态内部类、静态包等用法。今天咱们就对static的用法进行一次总结。
1、静态变量与静态方法
被static修饰的变量与方法,通常不需要new出来,就可以直接调用。(当然你也可以new一个出来,这样代码也不会报错,但是这会破会static代来的效果)
被static修饰的变量与方法,统一属于类的静态资源,是类实例间共享的。
在工作做,我们一般把工具类之中的一些方法和属性用static进行修饰,而在jdk中,也有很多这样的这样的类,例如Collections、Math等。
疑惑:静态方法能不能引用非静态资源?静态方法里面能不能引用静态资源?非静态方法里面能不能引用静态资源?比如就以这段代码为例,是否有错?
public class A
2 {
3 private int i = 1;
4
5 public static void main(String[] args)
6 {
7 i = 1;
8 }
9 }
上面这段代码的错误很明显,第7行中,会报出错。那么,我们不妨思考一下:
静态资源属于类,但是他是独立于类而存在的。从JVM的角度而言,在类加载的时候,静态资源是类初始化的时候加载的,而非new出来的。而普通的类则是new出来的,这就导致,在静态方法调用非静态资源的时候,对方还没有生成,如何调用?
所以,现在答案就非常明确了:
point1:静态方法不能调用非静态的方法。
point2:静态资源可以调用静态资源
point3:非静态资源可以调用静态资源。因为,静态的资源已经提前生成了。
静态代码块:
和静态变量与静态方法一样,他也是再初始化一个类的时候加载的,静态代码块只执行一次,且只在初始化的时候执行。不过需要注意的是:
1 public class A
2 {
3 private static int a = B();
4
5 static
6 {
7 System.out.println("Enter A.static block");
8 }
9
10 public static void main(String[] args){
11
12 }
14
15 public static int B()
16 {
17 System.out.println("Enter A.B()");
18 return 1;
19 }
20 }
得到的结果是:
Enter A.B() Enter A.static block
而,如果把第3行注释掉,则,结果为:
Enter A.static block
从而,我们得到的结论是:静态资源的加载是按照代码的顺序来执行的。而且,第二个结果也再次验证了,静态之间在加载的时候就可以开始调用了。
还有一点:
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行是有错的。静态代码块对于定义在它之后的静态变量,可以赋值,但是不能访问
最后一个小例子:
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要修饰一个类,这说明这个类是一个静态内部类。
public class Outer{ private static final int i = 1;
public static class StaticInner{ public void notStaticPrint(){ System.out.println("Outer.StaticInner.notStaticPrint(), i = " + i); } public static void staticPrint(){ System.out.println("Outer.StaticInner.staticPrint(), i = " + i); } }
}
public static void main(String[] args) {
Outer.StaticInner os = new Outer.StaticInner();
os.notStaticPrint();
Outer.StaticInner.staticPrint();
}
运行结果为:
Outer.staticInner.notStaticPrint(), i = 1
Outer.staticInner.staticPrint()
得出结论:
point1:静态内部类中可以有静态方法,也可以有非静态方法。
point2:静态内部类中可以访问外部类静态变量与静态方法。
point3:静态内部类不可以访问外部类的非静态的变量与方法。
point4:和普通的类一样,要访问静态内部类的静态方法,可以直接"."出来不需要一个类实例;要访问静态内部类的非静态方法,必须拿到一个静态内部类的实例对象
point5:注意一下实例化成员内部类和实例化静态内部类这两种不同的内部类时写法上的差别
(1)成员内部类:外部类.内部类 XXX = 外部类.new 内部类();
(2)静态内部类:外部类.内部类 XXX = new 外部类.内部类();
static修饰包---静态包(import static)
这个比较冷门,基本很少看见有地方用,使用JUnit可能会用到,写assert的时候会方便些。import static是JDK1.5之后的新特性,这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名.资源名,可以直接使用资源名。注意一下,import static必须这么写,而不能写成static import。举个例子来看一下:
2
3 public class A
4 {
5 public static void main(String[] args)
6 {
7 System.out.println(sin(2.2));
8 }
9 }
这么写意味着我导入了Math下的所有静态资源,main函数里面我就可以直接用sin(2.2)而不需要使用Math.sin(2.2)了。注意一下,要写import static java.lang.Math.*,最后的“.*”不可少,有了这两个字符才意味着导入的是Math下的所有静态资源,写成import static java.lang.Math是有问题的。当然,我们也可以指定只导入某个静态资源,比如只导入Math下sin这个方法而不导入Math下的所有静态资源:
1 import static java.lang.Math.sin;
2
3 public class A
4 {
5 public static void main(String[] args)
6 {
7 System.out.println(sin(2.2));
8 }
9 }
这么写也是没问题的。导入静态变量也是一样,有兴趣的可以自己试一下。对于import static,个人的态度是:
1、简化了一些操作,比如静态导入Math下的所有静态资源,在频繁使用Math类下静态资源的地方,可以少些很多“Math.”
2、降低了代码的可读性
建议在某些场景下导入特定的静态资源,不建议使用“.*”的导入方式。
浙公网安备 33010602011771号