Scala的原始類型是如何實現的
這些都是怎么實現的?實際上,Scala以與Java同樣的方式存儲整數:把它當作32位的字。這對在JVM上的效率以及與Java庫的互操作性方面來說都很重要。標準的操作如加法或乘法都被實現為原始操作。然而,當整數需要被當作(Java)對象看待的時候,Scala使用了“備份”類java.lang.Integer。如在整數上調用toString方法或者把整數賦值給Any類型的變量時,就會這么做。需要的時候,Int類型的整數能被透明轉換為java.lang.Integer類型的“裝箱整數”。
51CTO編輯推薦:Scala編程語言專題
所有這些聽上去都近似Java5里的自動裝箱并且它們的確很像。不過有一個關鍵差異,Scala里的裝箱比Java里的更少看見。嘗試下面的Java代碼:
你當然會得到true?,F在,把isEqual的參數類型變為java.lang.Integer(或Object,結果都一樣):
- // Java代碼
- boolean isEqual(int x,int y) {
- return x == y;
- }
- System.out.println(isEqual(421,421));
你會發現你得到了false!原因是數421被裝箱了兩次,因此參數x和y是兩個不同的對象。
- // Java代碼
- boolean isEqual(Integer x, Integery) {
- return x == y;
- }
- System.out.println(isEqual(421,421));
因為在引用類型上==表示引用相等,而Integer是引用類型,所以結果是false。這是展示了Java不是純面向對象語言的一個方面。我們能清楚觀察到原始類型和引用類型之間的差別。
現在在Scala里嘗試同樣的實驗:
實際上Scala里的相等操作==被設計為透明的參考類型代表的東西。對值類型來說,就是自然的(數學或布爾)相等。對于引用類型,==被視為繼承自Object的equals方法的別名。這個方法被初始地定義為引用相等,但被許多子類重載實現它們種族的相等概念。這也意味著Scala里你永遠也不會落入Java知名的關于字串比較的陷阱。Scala里,字串比較以其應有的方式工作:
- scala>def isEqual(x:Int, y:Int) = x == y
- isEqual:(Int,Int)Boolean
- scala>isEqual(421,421)
- res10:Boolean = true
- scala>def isEqual(x:Any, y:Any) = x == y
- isEqual:(Any,Any)Boolean
- scala>isEqual(421,421)
- res11:Boolean = true
Java里,x與y的比較結果將是false。程序員在這種情況應該用equals,不過它容易被忘記。
- scala>val x = "abcd".substring(2)
- x:java.lang.String = cd
- scala>valy="abcd".substring(2)
- y:java.lang.String=cd
- scala>x==y
- res12:Boolean=true
然而,有些情況你需要使用引用相等代替用戶定義的相等。例如,某些時候效率是首要因素,你想要把某些類哈希合并:hash cons然后通過引用相等比較它們的實例。 為這種情況,類AnyRef定義了附加的eq方法,它不能被重載并且實現為引用相等(也就是說,它表現得就像Java里對于引用類型的==那樣)。同樣也有一個eq的反義詞,被稱為ne。例如:
- scala>val x = new String("abc")
- x:java.lang.String = abc
- scala>val y = new String("abc")
- y:java.lang.String = abc
- scala>x == y
- res13:Boolean = true
- scala>x eq y
- res14:Boolean = false
- scala>x ne y
- res15:Boolean = true
Scala的相等性會在第28章中討論。
【相關閱讀】