2013-05-03 46 views
4

我有一個包裝類,可以存儲一個Long,Double或Boolean原始值(以及爲簡單起見我已刪除的其他一些東西)。我最初的樸素實現只是將包裝後的值存儲在Any類型的字段中,導致值被裝箱。如何將Scala @specialized用於基元周圍的內存有效包裝類?

要刪除拳擊和減少內存使用情況,我嘗試使用泛型,但得知由於類型擦除,這不會保存任何內容。所以我嘗試使用@specialized,但得到了令人驚訝的結果。

以下代碼是使用scalac 2.9.3構建的,並在JDK7上運行。 MemoryMeasurer來自here,我相信它是準確的。 「填充」字段不重要;我只是用它來填充基本對象(沒有包裝值)到16字節,所以我各種嘗試的效果更加清晰。

import objectexplorer.MemoryMeasurer 

class GenericNonSpecialized[A] (wrapped: A, val padding: Int) { 
    def getWrapped: Any = wrapped 
} 

class GenericSpecialized[@specialized(Long, Double, Boolean) A] (wrapped: A, val padding: Int) { 
    def getWrapped: A = wrapped 
} 

class GenericSpecializedVal[@specialized(Long, Double, Boolean) A] (val wrapped: A, val padding: Int) { 
    def getWrapped: A = wrapped 
} 

class NonGeneric(val wrapped: Long, padding: Int) { 
} 

object App { 
    def main(args: Array[String]) { 
    println(MemoryMeasurer.measureBytes(new GenericNonSpecialized(4L, 0))) 
    // Expect: 48: NonSpecialized object (24 bytes) + boxed long (24 bytes) 
    // Actual: 48 

    // I expect all of the below to be 24 bytes: Object overhead (12 bytes) + Long (8 bytes) + Int (4 bytes), 
    // but only the non-generic one is actually 24 bytes. 

    println(MemoryMeasurer.measureBytes(new GenericSpecialized(4L, 0))) // 56 

    println(MemoryMeasurer.measureBytes(new GenericSpecializedVal(4L, 0))) // 32 

    println(MemoryMeasurer.measureBytes(new NonGeneric(4L, 0))) // 24 
    } 
} 

問題:

  1. 如何創建一個使用24個字節,像非仿製藥的通用包裝對象? (我最好的嘗試,GenericSpecializedVal使用32)
  2. 爲什麼GenericNonSpecialized使用56字節,但如果我添加「val」,使「包裝」到一個實際的領域它下降到32字節?

回答

6

不幸的是,專門化的類繼承自其非專業化的父級,並且其中包含盒裝副本的存儲空間。因此,簡短的回答是,你不能以這種方式形成有效的包裝。

可以聲明在一個性狀的數據:

trait Boxer[@specialized A]{ def boxed: A } 

然後手動的實現:

class BoxerInt(val boxed: Int) extends Boxer[Int] 
class BoxerDouble(val boxed: Double) extends Boxer[Double] 

然後寫義和拳同伴重載應用方法:

object Boxer { 
    def apply(i: Int) = new BoxerInt(i) 
    def apply(d: Double) = new BoxerDouble(d) 
} 

這樣你就可以使它看起來像你不必做所有的工作:

val box = Boxer(5.0) 

但它仍然不完全無縫與專業化的其他用途(特別是在一般情況下創建將始終是一個問題)。

+0

案例類不適用於您的示例嗎? – Appleshell 2013-05-03 18:05:25

+0

@AdamS - 當然,但'case'比'val'長,否則對示例沒有任何幫助:) – 2013-05-03 18:14:20

+0

我只是好奇,因爲我從來沒有發現case case類的用法;(相對較新的對斯卡拉) – Appleshell 2013-05-03 18:17:04

相關問題