解釋 native,strictfp,transient,volatile:
ref:
http://www.iteye.com/topic/82640
- transient
變量修飾符。標記為transient的變量,在對象存儲時,這些變量狀態不會被持久化。當對象序列化的保存在存儲器上時,不希望有些字段數據被保存,為了保證安全性,可以把這些字段聲明為transient。
- volatile
volatile修飾變量。在每次被線程訪問時,都強迫從共享內存中重讀該成員變量的值。而且,當成員變量發生變化時,強迫線程將變化值回寫到共享內存。這樣在任何時刻,兩個不同的線程總是看到某個成員變量的同一個值。
看看Java Language Specification中的例子。
條件:一個線程不停的調用方法one(),一個線程不停的調用方法two()。我測試過多次,這種情況好像一直沒有出現。
class Test {
static int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
結果偶爾會出現j大於i的情況,因為方法沒有同步,所以會出現i和j可能不是一次更新。一種防止這種情況發生的辦法就是聲明兩個方法為synchronized 的。
class Test {
static int i = 0, j = 0;
static synchronized void one() { i++; j++; }
static synchronized void two() {
System.out.println("i=" + i + " j=" + j);
}
}
這樣可以防止兩個方法同時被執行,還可以保證j和i被同時更新,這樣一來i和j的值一直是一樣的。另外一種途徑就是把i和j聲明為volatile。
class Test {
static volatile int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
volatile的另一種解釋:
volatile 為一關鍵字 加在變數的前面
被 volatile 宣告的變數 將不會使用最佳化編譯
有時一個變數的值改變了 compiler 並不會馬上將他寫入記憶體中
而會先把結果放在CPU暫存器中 等到處理結束之後 才寫入記憶體
若說這個變數是多執行緒的flag 其他的執行緒要透過這個變數來反應
而這個值卻又沒有寫入記憶體 這時便會發生意想不到的結果
又或者是這變數為一個硬體的暫存器 會被硬體所改變
然而compiler 並沒有正確的將值從硬體暫存器取出來
而是將自己暫存的值拿來使用
這種情況 就是要用volatile 來宣告變數 告訴compiler不要自己暫存變數來提升速度
如此這個變數有任何的改變 便會馬上反應出來
JIT 和HotSpot 有何不同?
JIT 是完全編譯,不做任何選擇全部做最佳化。
HotSpot 則是分析bytecode,找出時常重覆執行的”HotSpot”,只將這部份轉成機器碼。
HotSpot的另外一個解釋:
改進JVM效能的技術之一,JAVA原始程式碼被編譯成bytecode後HotSpot探查程式執行時效率影響較大的程式碼片段,後對bytecode中這些片段動態編譯成原生碼,又對這些原生碼進行最佳化,從而提高執行效率。
Object Serialization:
1.Serializable介面中沒有定義任何方法(Method),其實它是一個Marker Interface,它只是告訴JVM此物件可以被序列化!!
2.
http://zzy1943.iteye.com/blog/634418
Generics:
泛型(Generics)
http://caterpillar.onlyfun.net/Gossip/JavaGossip-V1/JavaGossip.htm
簡單摘要一下...
為了達到"泛型"的功能,在一開始的時候,有一種作法是使用Object:
public class ObjectFoo {
private Object foo;
public void setFoo(Object foo) {
this.foo = foo;
}
public Object getFoo() {
return foo;
}
}
然後通過以下方法操作:
ObjectFoo foo1 = new ObjectFoo();
foo1.setFoo(new Boolean(true));
// 記得轉換介面
Boolean b = (Boolean) foo1.getFoo();
但是,有時候粗心大意,寫成...,造成錯誤...
ObjectFoo foo1 = new ObjectFoo();
foo1.setFoo(new Boolean(true));
[color=darkred]String s = (String) foo1.getFoo();[/color]
要命的是,語法上是可以的,所以編譯器檢查不出錯誤,真正的錯誤要在執行時期才會發生(ClassCastException)。所以這種設計不保險。
於是,我們換個寫法...
public class GenericFoo<T> {
private T foo;
public void setFoo(T foo) {
this.foo = foo;
}
public T getFoo() {
return foo;
}
}
而使用下面方法操作:
GenericFoo<Boolean> foo1 = new GenericFoo<Boolean>();
foo1.setFoo(new Boolean(true));
Boolean b = foo1.getFoo();
而這一次,如果我們誤寫錯了,在compile期間就會偵測出錯誤!
GenericFoo<Boolean> foo1 = new GenericFoo<Boolean>();
foo1.setFoo(new Boolean(true));
Integer b = foo1.getFoo();
P/s:如果使用泛型類別,但宣告時不一併指定型態呢?那麼預設會使用Object,不過您就要自己轉換物件的介面型態了,但編譯器會提出警訊,告訴您這可能是不安全的操作
JSP Bean scope:
Page:
載入的JavaBean其有效範圍只能夠在載入的那份JSP網頁中使用,當一離開這份JSP網頁,JavaBean隨即無效。
Session:
所載入的JavaBean的生命週期是起始於JavaBean的載入至使用者的Session失效為止,且不同的Session並不能互相使用所載入的JavaBean。
Application:
所載入的JavaBean其生命週期是起使於所載入的網頁至伺服器關閉,且JavaBean為公開的,任何一個JSP網頁皆能夠使用,且在任何JSP網頁中所載入的JavaBean是可以互相的使用,互相存取。