static关键字最基本的用法是:
1、被static修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要new出一个类来
2、被static修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要new出一个类来
3、被static修饰的变量、被static修饰的方法统一属于类的静态资源,是类实例之间共享的。
@ JDK把不同的静态资源放在了不同的类中为什么不把所有静态资源放在一个类里面呢?
主要有以下几个原因:
1、不同的类有自己的静态资源,这可以实现静态资源分类。比如和数学相关的静态资源放在java.lang.Math中,和日历相关的静态资源放在java.util.Calendar中,这样就很清晰了
2、避免重名。不同的类之间有重名的静态变量名、静态方法名也是很正常的,如果所有的都放在一起不可避免的一个问题就是名字重复,这时候怎么办?分类放置就好了。
3、避免静态资源类无限膨胀,这很好理解。
静态方法不可以引用非静态资源
例如下面代码:
public class A { private int i = 1; public static void main(String[] args) { //报错,静态方法内不能引用非静态属性 i = 1; } }
非静态方法里面可以引用静态资源
示例:
public class A { //静态属性 private static int i = 1; //非静态方法 public void main(String[] args) { i = 1; } }
静态资源属于类,但是独立于类存在的。从JVM的类加载机制的角度讲,静态资源是类初始化的时候加载的,而非静态资源是类new的时候加载的。
静态块
静态块也是static的重要应用之一。也是用于初始化一个类的时候做操作用的,和静态变量、静态方法一样,静态块里面的代码只执行一次,且只在初始化类的时候执行。
需要注意的三点:
1、Static修饰的方法执行顺序是怎么样的?
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
结论:静态资源的加载顺序是严格按照静态资源的定义顺序来加载的。
2、静态变量的赋值与创建
public class A { static { c = 3;
//报错 System.out.println(c); } private static int c; }
报错信息“Cannot reference a field before it is defined”。
结论:静态代码块对于定义在它之后的静态变量,可以赋值,但是不能访问。
3、继承类中静态代码块的加载顺序
public class A { static { System.out.println("A.static block"); } public A() { System.out.println("A.constructor()"); } }
public class B extends A { static { System.out.println("B.static block"); } public B() { System.out.println("B.constructor()"); } public static void main(String[] args) { new B(); new B(); } }
输出结果:
A.static block B.static block A.constructor() B.constructor() A.constructor() B.constructor()
结论:静态代码块是严格按照父类静态代码块->子类静态代码块的顺序加载的,且只加载一次。
注意:static一般情况下来说是不可以修饰类的,如果static要修饰一个类,说明这个类是一个静态内部类(注意static只能修饰一个内部类),也就是匿名内部类。
import static
这个比较冷门,基本很少看见有地方用,使用JUnit可能会用到,写assert的时候会方便些。import static是JDK1.5之后的新特性,这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名.资源名,可以直接使用资源名。注意一下,import static必须这么写,而不能写成static import。举个例子来看一下:
import static java.lang.Math.*; public class A { public static void main(String[] args) { System.out.println(sin(2.2)); } }
这样写意味着我导入了Math下的所有静态资源,main函数里面我就可以直接用sin(2.2)而不需要使用Math.sin(2.2)了。注意一下,要写import static java.lang.Math.*,最后的“.*”不可少,有了这两个字符才意味着导入的是Math下的所有静态资源,写成import static java.lang.Math是有问题的。当然,我们也可以指定只导入某个静态资源,比如只导入Math下sin这个方法而不导入Math下的所有静态资源:
import static java.lang.Math.sin; public class A { public static void main(String[] args) { System.out.println(sin(2.2)); } }
对于import static,个人的态度是:
1、简化了一些操作,比如静态导入Math下的所有静态资源,在频繁使用Math类下静态资源的地方,可以少些很多“Math.”
2、降低了代码的可读性
建议在某些场景下导入特定的静态资源,不建议使用“.*”的导入方式。
知识点:
1、Java中的static关键字不会影响到变量的变量或者方法的作用域。
2、虽然对于静态方法来说没有this,但是我们在非静态方法中能够通过this访问静态方法成员变量。
示例:
public class Test { //静态变量 static int value = 11; //静态方法 public static void main(String[] args) { new Test().printValue(); } //非静态方法 private void printValue() { int value = 22; //运用this访问静态变量 System.out.println(this.value); } }
输出结果为:11
这里的this表示的是当前对象,那么通过new Test()来调用printValue的话,当前对象就是通过new Test()生成的对象。而static变量是被对象所享有的,因此在printValue中的this.value的值毫无疑问是11。