大可制作:QQ群:31564239(asp|jsp|php|mysql)

Java Gossip: 关于 static 成员

对于每一个基于相同类所产生的对象而言,其拥有各自的数据成员,然而在某些时候,您会想要这些对象拥有相同的数据成员,其数据是共享的。

举个例子来说,在Ball类中,您会使用到圆周率的这个数据,对于任一个球而言,圆周率都是一样的,您并不需要让不同的球对象拥有各自的数据成员来记录圆周率,而这个记录的值却是相同,这只会增加内存的消耗而已。

您可以将数据成员声明为"static",被声明为"static"的数据成员,它是属于类所拥有,而不是个别的对象,您可以将"static"视为个别对象所拥有、共享的数据成员。

要声明static变量,您只要在声明数据成员时加上"static"关键字就可以了,例如:
public class Ball {
    // ....
    public static double PI = 3.14159; // 声明static数据
 
    public Ball() {
        // ..
    }
 
    public Ball(double radius, String name) {
        //...
    }
 
    public double getVolumn() {
      // ......
    }
}
 
由于static成员属于类所拥有,所以在不使用对象名称的情况下,您也可以使用类名称加上 . 运算符来存取static数据成员,例如:
System.out.println("PI = " + Ball.PI);

static变量同样遵守public、protected与 private的存取限制,所以若您要在类之外直接存取static变量,必须注意它的权限(例如必须设定为public成员)。

虽然您也可以在声明对象之后,使用 . 运算符来存取static数据成员,但是这并不被鼓励,通常建议使用类名称加上 . 运算符来存取,一方面也可以避免与非static成员混淆。

与静态数据成员类似的,您也可以声明方法成员为static方法,又称静态方法,被声明为静态的方法通常是为了提供工具,例如在Ball类上增加一个角度转径度的方法toRadius():
public class Ball {
    ...
    public static double toRadius(double angle) {
         return 3.14159 / 180 * angle;
    }
}

与静态数据成员一样的,您可以透过类名称使用'.'运算符来存取static方法(当然要注意权限设定,例如设定为public),例如:
System.out.println("角度90等于径度" + Ball.toRadius(90));
 

静态数据与静态方法的作用通常是为了提供共享的数据或工具方法,例如将数学常用常量或计算公式,以static声明并撰写,之后您可以把这个类当作工具,透过类名称来管理与取用这些静态数据或方法,例如像J2SE 所提供的Math类上,就有Math.PI这个静态常量,以及Math.Exp()Math.Log()Math.Sin()等静态方法可以直接使用,另外还有像Integer.parseInt()Integer. MAX_VALUE等也都是静态方法与静态数据成员的实际例子。

由于static成员是属于类而不是对象,所以当您调用static方法时,并不会传入对象的位置引用,所以static方法中不会有 this引用,由于没有this引用,所以在Java的static方法成员中不允许使用非static成员,因为程序没有this来指向对象位址,也 就无法辨别要存取哪一个对象的成员,事实上,如果您在static方法中使用非static数据成员,在编译时就会出现以下的错误讯息:
non-static variable test cannot be referenced from a static context

或者是在static函数中调用非static函数,在编译时就会出现以下的错误讯息:
non-static method showMe() cannot be referenced from a static context

Java在使用到类时才会加以载入程序中,如果您要使用一个static数据或方法,而在载入一个类时,您希望先进行一些初始化动作,您可以使用static定义一个区块,并在当中撰写初始化资源的动作,例如:
public class Ball {
    public static int[] arr = new int[10];
    static {
        // 一些初始化程序码
    }

    ....
}
 

像上面这样一个类,在第一次调用而被载入时,static区块中的程序码就会被执行,且只会执行一次,要注意的是,static属性成员必须撰写在 static区块之前,而如果在static区块中发生了异常,则最后会被包装为 java.lang.ExceptionInInitializerError。