前言:
以下大部分内容我从谷歌上搜索,结合官方的文档总结的。我认为会使用谷歌、会阅读官方的文档非常作用,这里都是最权威的参考。
Java中的Static关键字用的很多,但是总结起来,大概有:Static member、Static Block、Static import三部分内容。下面分别介绍
1. Static Entry
Static试题包括静态变量、静态方法、静态内部类。
首先理解一下Static这个词,在Java中,这个词的意思是这些实体归类所有,与类绑定在一起,所有该类的实例共享这些实体。例如同一个厂商生产的自行车,把自行车抽象为一个类,对象就是每一辆自行车。每一辆自行车有价格、颜色等属性,这些属性每一辆自行车都不一样,但是,他们的声场厂商都是一样的,这个时候就可以把生产厂商定义成一个静态类型。Static实体在内存中单独存放,不跟对象的变量存放在一起。
1.1 静态变量:
定义如下:
- private static int VENDOR = 'ABC' ;
一般情况下,我们将静态变量用大写字母表示,有多个单词的时候,用下划线分开。静态变量也成为类变量,顾名思义,这些变量属于类的,而不是实例对象的。对于特定的类加载器来说,只存在一个静态变量,无论你创建多少个对象,或者你根本就没有创建对象。注意我的前提,对于特定的类加载器,也就是说,不同的类加载器可能会有多个讲台变量。访问静态变量时,可以直接通过类访问:ClassName.VENDOR. 当然也可以通过实例访问,不过不建议那么做,因为体现不出“静态”二字。
那么,在哪些地方可以声明静态变量呢?对于一般的类中,可以在类中直接声明(与方法并列),注意不能在方法中声明静态变量,不管该方法是否为静态。在内部类当中,情况有些不一样,非静态内部类中不能声明静态变量(事实上,非静态内部类不能声明任何静态试实体)。静态内部内则可以声明静态变量。一句话,静态变量只能在外层类中或者静态内类中定义。
1.2 静态方法:
定义格式如下:
- public static void doSomething() {...
一样的,静态方法也属于类所有,但是对象一样可以调用。静态方法一般用于对静态变量进行操作,在静态方法中,不能直接引用非静态变量。因为非静态变量属于某个实例所有,如果还没有创建对象,那就没有实例变量存在,请问如何引用??如果要引用非静态变量,只能通过对象引用。静态方法中不能引用this、super这些关键字。
最常见的静态方法当然是main()方法。因为在其他所有对象创建之前,main方法就必须被调用,此时只能通过类来调用这个main方法。在main方法中,是不能直接引用非静态变量的。
- public class StaticMethod {
-
- private int age = 0 ;
- private static String VENDOR = "JAC";
-
-
-
-
- public static void main(String[] args) {
-
-
-
- System.out.println(age);
-
-
-
- System.out.println(VENDOR);
-
- }
-
- }
静态方法中同样不能直接调用非静态方法,只能通过对象引用。总结一下:实例方法可以直接访问实例变量、静态变量,可以直接调用实例方法、静态方法。但是,静态方法只能直接访问静态变量、调用静态方法,如果要访问非静态变量或方法,只能通过对象引用。举例如下:
- public class StaticMethod {
-
- private int age = 0 ;
- private static String VENDOR = "JAC";
-
- public void show() {
- System.out.println("Non-Static");
- }
-
- public static void staticShow() {
- System.out.println("Static");
- }
-
- public static void main(String[] args) {
-
- System.out.println(VENDOR);
- staticShow();
-
- StaticMethod staticMethod = new StaticMethod();
- System.out.println(staticMethod.age);
- staticMethod.show();
-
- }
-
- }
那么,在哪里可以定义静态方法呢?官方说法是这样的,Static methods can only be declared in a static or top-level type.也就是说,在外层的类中,可以定义静态方法。但是在内层的类当中,只有静态的内部类才能定义静态方法。跟静态变量的情况其实是一样的。
1.3 静态类
只能在内部类中定义静态类。也就是说,内部类有静态和非静态之分。静态内部类与外层类绑定,即使没有创建外层类的对象,它一样存在。但是非静态内部类不一样,它是与特定的外层类对象绑定的,只有外部类对象存在,内部类才存在。
内部静态内中的方法一样有静态与非静态之分,如果是静态方法,在外层中可以通过内部静态内直接调用,如果是非静态方法,则必须先创建内部静态类的对象之后再调用。
- public class Test{
-
- public static void main(String[] args) {
- StaticInnerClass.diaplay();
- StaticInnerClass i = new StaticInnerClass();
- i.test();
-
- }
-
- static class StaticInnerClass {
- private static String VENDOR = "JAC";
- private static void diaplay() {
- System.out.println("Inner static class, static method");
- }
-
- private void test() {
- System.out.println("Inner static class,non-static methon");
- }
-
- }
-
- }
至于非静态内部类,不是本文的探讨内容,参考http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html。静态实体的探讨就到这里。
2. Static Block
静态块的格式如下:(下面是一个完整例子,接下来说明用)
- import java.util.HashMap;
- import static java.lang.Math.PI;
-
-
-
-
-
-
-
- public class StaticBlock {
-
- {
- System.out.println("Instance Initializer, run when an object is created! ");
- }
-
-
-
- private static final HashMap<String, String> MAP = new HashMap<String, String>();
- static {
- MAP.put("banana", "honey");
- MAP.put("peanut butter", "jelly");
- MAP.put("rice", "beans");
- }
- static {
- System.out.println("Static Initializer, run when the class is loaded!");
- MAP.put("cons", "cons");
- }
-
-
-
-
-
- public static void main(String[] args) {
- new StaticBlock();
- new StaticBlock();
- new StaticBlock();
- System.out.println(MAP);
-
-
-
-
-
-
-
- System.out.println(PI);
-
- }
-
- }
static { }这一部分就是静态块,当类加载器载入类的时候,这一部分代码被执行,常用于对静态变量进行初始化工作。当然,可以声明一个静态方法来完成这些初始化工作,这样做的好处就是这些初始化工作可以再次被调用,而在初始化块中,代码只能执行一次,不能再调用。在静态块中,可以访问静态变量,调用静态方法。
如果去掉static,{ }中的代码则会在创建类对象的时候才执行,(相当于把这部分代码复制到各个构造函数中)这样可以实现块中的内容在多个构造函数中的复用。上面的代码输出结果如下:
- Static Initializer, run when the class is loaded!
- Instance Initializer, run when an object is created!
- Instance Initializer, run when an object is created!
- Instance Initializer, run when an object is created!
- {banana=honey, rice=beans, peanut butter=jelly, cons=cons}
- 3.141592653589793
可以看到, static{ }中的代码只执行一次,而{ }中的代码每当创建一个新对象的时候就会被执行。{ } 这样的代码块也被称为构造函数块(Constructor Block)。再举个例子:
- package learn.study;
-
- public class StaticExample{
- static {
- System.out.println("This is first static block");
- }
-
- public StaticExample(){
- System.out.println("This is constructor");
- }
-
- public static String staticString = "Static Variable";
-
- static {
- System.out.println("This is second static block and refer to STATIC VARIABLES:"
- + staticString);
- }
-
- public static void main(String[] args){
-
-
- staticMethod2();
- }
-
- static {
- System.out.println("This is third static block and refer to STATIC METHOD");
- staticMethod();
- }
-
- public static void staticMethod() {
- System.out.println("This is static method");
- }
-
- public static void staticMethod2() {
- System.out.println("This is static method2");
- }
- }
输出:
- This is first static block
- This is second static block and refer to STATIC VARIABLES:Static Variable
- This is third static block and refer to STATIC METHOD
- This is static method
- This is static method2
当然,静态块也有它的局限性,比如静态块代码大小不能超过JVM规定的某个值,不能用this,super关键字,不能从静态块中返回值,增加调试难度等等。因此,必须小心处理静态块中可能出现的异常。
3. 静态导入:
最后提一下静态导入,如上面的代码: static import java.lang.Math.PI
看上面的注释,import之后,我们可以省略Class前面的包名直接使用类,如System.out.println(Math.PI).
静态导入之后,可以把类名也省略掉,直接使用类当中的变量或者方法,即System.out.println(Math.PI).静态导入虽然有它的一些方便,但使用的时候要非常小心。参考官方文档:http://docs.oracle.com/javase/1.5.0/docs/guide/language/static-import.html
版权所有,转载请注明来源。