從Java 5開始引入了靜態導入語法(import static),其目是為了減少字符輸入量,提高代碼的可閱讀性,以便更好地理解程序。我們先來看一個不使用靜態導入的例子,也就是一般導入:
public class MathUtils{
//計算圓面積
public static double calCircleArea(double r){
return Math.PI*r*r;
}
//計算球面積
public static double calBallArea(double r){
return 4*Math.PI*r*r;
}
}
這是很簡單的數學工具類,我們在這兩個計算面積的方法中都引入了java.lang.Math類(該類是默認導入的)中的PI(圓周率)常量,而Math這個類寫在這裡有點多餘,特別是如果MathUtils中的方法比較多時,如果每次都要敲入Math這個類,繁瑣且多餘,靜態導入可解決此類問題,使用靜態導入後的程序如下:
import static java.lang.Math.PI;
public class MathUtils{
//計算圓面積
public static double calCircleArea(double r){
return PI*r*r;
}
//計算球面積
public static double calBallArea(double r){
return 4*PI*r*r;
}
}
靜態導入的作用是把Math類中的PI常量引入到本類中,這會使程序更簡單,更容易閱讀,只要看到PI就知道這是圓周率,不用每次都要把類名寫全了。但是,濫用靜態導入會使程序更難閱讀,更難維護。靜態導入後,代碼中就不用再寫類名了,但是我們知道類是「一類事物的描述」,缺少了類名的修飾,靜態屬性和靜態方法的表象意義可以被無限放大,這會讓閱讀者很難弄清楚其屬性或方法代表何意,甚至是哪一個類的屬性(方法)都要思考一番(當然,IDE友好提示功能是另說),特別是在一個類中有多個靜態導入語句時,若還使用了*(星號)通配符,把一個類的所有靜態元素都導入進來了,那簡直就是惡夢。我們來看一段例子:
import static java.lang.Double.*;
import static java.lang.Math.*;
import static java.lang.Integer.*;
import static java.text.NumberFormat.*;
public class Client{
//輸入半徑和精度要求,計算面積
public static void main(Stringargs){
double s=PI*parseDouble(args[0]);
NumberFormat nf=getInstance();
nf.setMaximumFractionDigits(parseInt(args[1]));
formatMessage(nf.format(s));
}
//格式化消息輸出
public static void formatMessage(String s){
System.out.println("圓面積是:"+s);
}
}
就這麼一段程序,看著就讓人火大:常量PI,這知道,是圓周率;parseDouble方法可能是Double類的一個轉換方法,這看名稱也能猜測到。那緊接著的getInstance方法是哪個類的?是Client本地類?不對呀,沒有這個方法,哦,原來是NumberFormate類的方法,這和formateMessage本地方法沒有任何區別了——這代碼也太難閱讀了,非機器不可閱讀。
所以,對於靜態導入,一定要遵循兩個規則:
不使用*(星號)通配符,除非是導入靜態常量類(只包含常量的類或接口)。
方法名是具有明確、清晰表象意義的工具類。
何為具有明確、清晰表象意義的工具類?我們來看看JUnit 4中使用的靜態導入的例子,代碼如下:
import static org.junit.Assert.*;
public class DaoTest{
@Test
public void testInsert(){
//斷言
assertEquals("foo","foo");
assertFalse(Boolean.FALSE);
}
}
我們從程序中很容易判斷出assertEquals方法是用來斷言兩個值是否相等的,assertFalse方法則是斷言表達式為假,如此確實減少了代碼量,而且代碼的可讀性也提高了,這也是靜態導入用到正確地方所帶來的好處。