2012/10/23

alert('8' > '10'); // true?

在javascript內字串比較是依據長度,由左而右依序比較,規則是:
  • 相等則往下一位字元比較,反之則得出結果
  • 有值的比沒值的大

A的編碼是0041
B的編碼是0042
alert(‘A’ > ‘AB’); // false,因為最高位(最左邊)字元相等,而AB比較長
alert(‘B’ > ‘AB’); // true,最高位字元B比A大

再來看 ‘8’,‘1’,‘0’
0的編碼為0030
1的編碼為0031
8的編碼為0038
alert(‘8’ > ‘10’); // true
由於最高位’8’比’1’來的大,所以結果為true

2012/04/16

ResouseBundle.getBundle(String)在static情境下的問題


如果在一個static block或是static變數中呼叫ResourseBundle.getBundle(String)
在某些特定的情況下可能會造成MissingResourceException

其原因出在官方文件中敘述此method等同於呼叫
getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())

問題在於this.getClass().getClassLoader()的部分,this在static內是取不到參照的
而實際上底層的實作是透過下列這段code取得ClassLoader
/*
 * Automatic determination of the ClassLoader to be used to load
 * resources on behalf of the client.  N.B. The client is getLoader's
 * caller's caller.
 */
private static ClassLoader getLoader() {
    Class[] stack = getClassContext();
    /* Magic number 2 identifies our caller's caller */
    Class c = stack[2];
    ClassLoader cl = (c == null) ? null : c.getClassLoader();
    if (cl == null) {
        // When the caller's loader is the boot class loader, cl is null
        // here. In that case, ClassLoader.getSystemClassLoader() may
        // return the same class loader that the application is
        // using. We therefore use a wrapper ClassLoader to create a
        // separate scope for bundles loaded on behalf of the Java
        // runtime so that these bundles cannot be returned from the
        // cache to the application (5048280).
        cl = RBClassLoader.INSTANCE;
    }
    return cl;
}

這樣會導致你取得的ClassLoader跟預期的結果不同
進而取不到目標resource

若要在static中使用ResourceBundle.getBundle(String)最好的方式還是自行呼叫
ResourseBundle.getBundle(baseName, Locale.getDefault(), [TargetClass].class.getClassLoader())

2011/10/04

Java中的Singleton實作

在Java 1.5之前
以往我們可能用提供 private constructor 和 static final field 的方式,來確保只會得到唯一的 Class 實例
/* 
 * 獨一無二的貓王(Elvis),這世上就只有一個貓王 
 * Singleton with public final field 
 */
public class Elvis {
   public static final Elvis INSTANCE = new Elvis();
   private Elvis() { //忽略細節 }
   public void leaveTheBuilding() { //忽略細節 }
}
當需要取得貓王實例時,簡單的存取 Elvis.INSTANCE 即可。不過 private constructor 依然有一個問題,用 reflection 機制的 AccessibleObject.setAccessible 可以破解 private 的限制,如果要防範此一漏洞,還是得在 constructor 內做些手腳。


或是用 static factory 的方式,來提供唯一的 Class 實例
/* 
 * 獨一無二的貓王(Elvis),這世上就只有一個貓王 
 * Singleton with static factory
 */
public class Elvis {
   private static final Elvis INSTANCE = new Elvis();
   private Elvis() { //忽略細節 }
   public static Elvis getInstance() { return INSTANCE; }
   public void leaveTheBuilding() { //忽略細節 }
}
雖然有同上的問題(private constructor 部分),但是此作法相較起來更有彈性,如果你改變了想法,不想用 singleton 的方式實作此 Class,可以在不變動 API 的情況下修改 getInstance() 達成。


但是無論用上面哪種方式,當你需要一個 Serializable 的 Singleton 時,都會遇到一個同樣的問題:每次 deserialize 時都會建立一個新的實例。

解法就是將所有 field 宣告為 transient,並加上 readResolve 方法
// readResolve method to preserve singleton property
private Object readResolve() {
   // Return the one true Elvis and let the garbage collector
   // take care of the Elvis impersonator.
   return INSTANCE;
}
如果有定義此方法,則它會自動在 deserialize 時被呼叫,並回傳我們指定的物件。

Java 1.5之後的最好的實作方式
現在有了第三種簡明又實用的新解法 - 實作單一元素的 Enum。
// Enum singleton - the preferred approach
public enum Elvis {
   INSTANCE;
   public void leaveTheBuilding() { ... }
}
這種做法接近 public final field 而且
  • 程式碼更簡潔
  • 沒有 private constructor 漏洞
    (因為 Enum 型別像抽象類別一樣不能被實例化)
  • 本身還提供了 Serialization 機制
  • Enum 本身的特性確保只會有一個實體

所以單一元素的 Enum 是目前最好的 Singleton 實作方式。

2011/09/28

Eclipse Plugin開發遇到No Schema Found的問題

開發 Plugin 時遇到一個問題,在設定 plugin.xml 內的 Extensions 時,遇到 no schema found for the 'org.eclipse.ui.views' extension point 這樣的訊息,而且右鍵點該 Extension 只能 New → Generic,無法建立對應的元件...

google 了一下之後發現原來跟 Eclipse plugin 的 library 有關,上官網查了一下後,發現原來我用的 J2EE 版並沒有含 PDE/RCP 套件的 source code,所以也就沒有含 schema 和其他文件。

既然知道原因,那就比較好解了,Classic 版的 PDE/RCP 套件是有含 source code 的,於是重新抓相同版號(這裡用 3.6.2)的 Eclipse 下來,將對應的 source code jar 檔複製到 Eclipse 安裝目錄/plugins 下就好了,個人是整個把 plugins 目錄覆蓋掉,懶人作法 ._.

怕有衝突的話最好先做個備份,或是用 import library 的方式把 Classic 版的 plugin library 加到 project 也行。

2011/09/26

java中的Class.this


首先先複習一下基本:
在 Java 的 Class 內宣告的 Class,稱為 Nested Class(巢狀類別)。

Nested Class 又分為 static 和 non-static 兩種,其中加上 static 宣告的就叫做 Static Nested Class;而 non-static 的 Nested Class 又稱為 Inner Class(內部類別)。

Inner Class 還可以再細分為三種又是另外一個故事了,這邊就不提
那 Class.this 究竟是代表甚麼呢...
public class ClassThisTest {
	public static void main(String[] args) {
		OuterClass outerInst1 = 
				new OuterClass("Outer class no.1");
		OuterClass.InnerClass innerInst1 = 
				outerInst1.new InnerClass();
		
		System.out.println(innerInst1.toString()); 
											//Inner class
		System.out.println(innerInst1.outerToString()); 
											//Outer class no.1
												   
		OuterClass outerInst2 = 
				new OuterClass("Outer class no.2");
		OuterClass.InnerClass innerInst2 = 
				outerInst2.new InnerClass();
		
		System.out.println(innerInst2.outerToString()); 
											//Outer class no.2
	}	
}

class OuterClass {
	private String outerMsg;
	
	public OuterClass(String msg) {
		this.outerMsg = msg;
	}
	
	public String toString() {
		return outerMsg;
	}
	
	public class InnerClass {
		private final String innerMsg = "Inner class";
		
		public String toString() {
			return innerMsg;
		}
		
		public String outerToString() {
			//Class.this
			return OuterClass.this.toString();
		}
	}
}
簡單說就是 Inner Class 用來參照相依的 Outer Class 實體用的。

因為在 Inner Class 裡面用 this 關鍵字的話,將會指向 Inner Class 實體,所以若是需要參照 Outer Class 實體時,用 Class.this 的方式就可以了。