Java中的關鍵字不少,至少有50個左右,常見的new,final,try,catch等等,其中大多數關鍵字的意義都很簡單,基本上根據英文意思就能知道其功能,本文不會對那些簡單的關鍵字作介紹,僅挑選了幾個使用頻率較高,但又可能致使「迷惑」的關鍵字來討論。java
transient關鍵字可修飾於類成員變量,做用是當類的對象發生序列化的時候,最終的序列化內容不包括被修飾的成員變量。下面的代碼演示了transient的功能:編程
public class User implements Serializable {
private String username;
private transient String password;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
//setter and getter
}
public class TransientTest {
public static void main(String[] args) {
User user = new User();
user.setUsername("yeonon");
user.setPassword("admin");
System.out.println("在序列化以前:");
System.out.println(user);
System.out.println("----------------------");
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(
"E:\\Java_project\\effective-java\\src\\top\\yeonon\\ch11\\user.txt"))){
oos.writeObject(user);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("E:\\Java_project\\effective-java\\src\\top\\yeonon\\ch11\\user.txt"))){
User user1 = (User) ois.readObject();
System.out.println("序列化以後讀取到的:");
System.out.println(user1);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
複製代碼
User類首先得實現Serializable接口,而後我在password成員變量上增長了transient關鍵字,在主類中,用ObjectOutputStream和ObjectInputStream來作序列化和反序列化。安全
執行後的輸出結果以下:併發
在序列化以前:
User{username='yeonon', password='admin'}
----------------------
序列化以後讀取到的:
User{username='yeonon', password='null'}
複製代碼
發現序列化以後,再讀取時,password是null,這說明序列化的內容沒有包括password。ide
順便說一下,在實際寫代碼的時候最好不要使用user1這種變量名,這裏只是爲了方便,隨手寫的。學習
這是一個二元操做符,也算是關鍵字,做用是判斷左邊的對象是不是右邊類的實例。以下所示:spa
User user = new User();
if (user instanceof User) {
System.out.println("user object is instance of User class");
} else {
System.out.println("user object is'n instance of User class");
}
複製代碼
這裏確定會輸出user object is instance of User class。若是咱們將User替換成Object,也同樣會輸出這段話,這說明instanceof還能夠用於繼承體系,便可以用來判斷繼承體系中子類的實例是不是父類的實現。線程
這個多用於併發環境下,功能有兩個:code
關於volatile的介紹,在我以前的文章 Java虛擬機(二):Java內存模型 有詳細解釋,在此再也不贅述。對象
和volatile同樣,多用於併發環境下,其做用就是給某個代碼段或者方法加上內置鎖。拿併發編程中的「Hello,World」來舉個例子:
public class SyncTest {
private int count = 0;
public void add() {
count += 1;
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException, TimeoutException, ExecutionException {
ExecutorService service = Executors.newFixedThreadPool(4);
SyncTest syncTest = new SyncTest();
for (int j = 0; j < 4; j++) {
service.execute(() -> {
for (int i = 0; i < 10000; i++) {
syncTest.add();
}
});
}
service.shutdown();
service.awaitTermination(1000, TimeUnit.SECONDS);
System.out.println(syncTest.getCount());
}
}
複製代碼
這裏輸出的結果會是什麼呢?40000?答案是不必定,多是40000,也多是比40000小的數,但確定不會比40000大,由於這裏至少有4個線程在併發的對count進行修改,而又沒有什麼同步措施,故答案不對。若是在add方法上加入synchronized關鍵字,就能夠保證線程安全了,以下所示:
public synchronized void add() {
count += 1;
}
複製代碼
這樣以後,不管運行多少次代碼,結果都會是40000。由於synchronized其實是內置鎖,同一時刻僅有一個線程能獲取到鎖,並對其進行修改,最後執行完畢釋放鎖,其餘線程可再次競爭鎖,而後如此往復,知道任務完成。
那synchronized除了做用在方法還能做用在哪呢?下面是synchronized的使用方式:
做用在實例方法上(沒有static修飾的方法),至關於給對應的對象加鎖,即也不能訪問該對象其餘的有synchronized修飾的方法,其餘實例對象不受影響。
做用靜態方法上,至關於給類加鎖,此時的做用範圍就是該類的全部實例對象,即該類的全部對象同一時刻只能訪問有一個對象能訪問到synchronized靜態方法,並且不能訪問該類的其餘synchronized靜態方法。
做用在代碼塊中,以下所示:
private String lock = "lock";
synchronized(lock) {
//do something
}
//或者
synchronized(Test.class) {
//do something
}
複製代碼
這又有兩種狀況,一種是括號裏的是對象實例,這種狀況是對對象實例加鎖,對其餘對象沒有影響。另外一種是括號裏的是類對象,這種狀況是對類加鎖,該類的其餘對象都會受到影響。
關於synchronized的其餘內容(例如在虛擬機裏是如何實現的?有哪些相應的指令?)就很少說了,比較本文不是專門講併發的。
final最容易讓人記住的功能就是將一個變量聲明成常量了,但實際上它的做用不只僅是這個,還能夠防止指令重排,在我以前的文章Java虛擬機(二):Java內存模型有比較詳細的介紹,在此再也不贅述。
static的做用也比較明顯,就是將類、方法、成員變量聲明成靜態的。
靜態類做用就是方便使用,若是一個類不依賴外部類的成員變量、方法等,那麼最好將其聲明成靜態類。
靜態方法其實也是爲了方便使用,在調用的時候能夠直接經過類名.方法的形式調用而不須要建立一個新的實例對象,靜態工廠模式就很是依賴這個特性。
靜態成員變量仍是爲了方便使用,咱們常常能在程序源代碼中看到相似public static final String XXX = "YYY"的聲明,這是由於靜態變量能夠直接訪問,不管是在實例方法裏,仍是靜態方法裏都同樣,這樣就能避免經過參數傳遞了。
本文簡單的介紹了幾個經常使用的關鍵字,但實際上它們的功能或者原理都遠遠不止於此,若是想深刻了解,建議到網上搜索資料進行學習。