2011-11-23 33 views
7

一個複雜的按鍵我有一個點對象:爲番石榴緩存(移動)

class Point { 
    final int x,y; 
    ... 
    } 

因爲這點,將用於/在我的代碼創建了所有的地方,我要開始使用番石榴緩存。不幸的是,CacheLoader只接受一個參數。 Another question這裏在stackoverflow使用一個對象類似的問題。但我不喜歡爲每個緩存請求創建一個虛擬對象。 所以我想出了我自己的解決方法:

因爲對象是由x和y指定的,所以我認爲我可以將兩個值合併(移位)爲long,這將是我的關鍵。

void test(int x, int y) { 
    Long key = (long) ((long) (x) << Integer.SIZE | y); 
    Point point = cache.get(key); 
} 

CacheLoader<Long, Point> loader = new CacheLoader<Long, Point>() { 
    public Point load(Long key) throws Exception { 
    final int x,y; 
     // shift magic 
     x = (int) (key >> Integer.SIZE); 
     y = key.intValue(); 
     return new Point(x, y); 
    } 
}; 

我其實是一個班次noob。這會工作嗎?我錯過了什麼?這是否比雙人班「更快」?這是我的問題!

是的,我測試的代碼,它的工作到目前爲止,我可以告訴。

+3

讓人驚訝。 *請*創建一個真正的對象(有兩個命名的領域)的重點!您已經創建了一個'dummy'對象,一個java.lang.Long,更加模糊。 –

回答

7

這個怎麼樣?您的Point課程必須正確實施equals()hashcode()

static class Points { 
    static final Interner<Point> INTERNER = Interners.newStrongInterner(); 

    public static Point cached(final int x, final int y) { 
    return INTERNER.intern(new Point(x, y)); 
    } 
} 

你的實際目的是緩存相等的對象,對嗎?比這將滿足您的需求。 用法:

Point center = Points.cached(0, 0); 

或者緩存例子的調整版本:

CacheLoader<Point, Point> loader = new CacheLoader<Point, Point>() { 
    @Override 
    public Point load(final Point point) { 
    return point; 
    } 
} 
... 
Point center = cache.get(new Point(0, 0)); 
+0

嗯,這個干擾者對我來說是新的。看起來很有趣。謝謝! 當然是'equals'和'hashcode'正確實現。我不希望布洛赫先生把我帶入Java地獄:-D –

+4

Ouch。非常糟糕的主意。首先,你將物體的生命週期縮短(對於所有垃圾收集器來說是小菜一碟),這會讓所有未來的gc都變慢。然後,這個東西變得無限,與內存泄漏沒有太大的區別。第三,爲了在內存方面達到平衡,*所有緩存點必須至少保留在兩個地方*。只有當它們被更多地重用時纔會有任何記憶保存。更不用說,除了查找之外,這些對象不需要保留,更不用說留在兩個地方了。我會考慮刪除這個答案: - \ –

+0

你說得對。 StrongInterner實現將存儲點直到結束。 Interners.newWeakInterner()會做的。只有在真正重複使用點時才能獲得好處。 – bjmi

2

它可能更快(如果差異是可測量的),但配對類將使您的代碼更好地理解或重用。我會用一個通用的Pair類:

public final class Pair<L, R> { 

    private final L left; 
    private final R right; 

    private Pair(L left, R right) { 
     this.left = left; 
     this.right = right; 
    } 

    public static <L,R>Pair<L,R> of(L left, R right){ 
     return new Pair<L, R>(left,right); 
    } 

    @Override 
    public boolean equals(final Object obj) { 
     if (obj instanceof Pair) { 
      final Pair<?,?> other = (Pair<?,?>) obj; 
      return Objects.equal(left, other.left) 
       && Objects.equal(right, other.right); 
     } else { 
      return false; 
     } 
    } 

    @Override 
    public int hashCode() { 
     return Objects.hashCode(left, right); 
    } 

    @Override 
    public String toString() { 
     return MoreObjects.toStringHelper(this) 
         .add("left", left) 
         .add("right", right) 
         .toString(); 
    } 

} 

一旦你在你的代碼庫中,你會發現它的多個用途。位移不是真的像Java一樣(儘管其他許多人會不同意)。

Guava docs

+0

好的,差別可能無法衡量。得到它了! 但你提到的缺點是什麼?!首先,這是我的一個問題。 –

+1

@MarcelJaeschke使用對象使您的代碼可讀,易於理解和可重用。位移不。如果你問我,這是過早的優化。 –

+0

是的,我很瞭解OOP的概念!但我認爲你的方式只是一種過度工程!對象點只包含兩個int字段。你們倆的班級有這兩場!實際上你創建了一個對象的副本!所以你可以首先將對象用作關鍵字! (對不起,格式): Point point = new Point Point pointFromCache = cache.get(point); CacheLoader loader = new CacheLoader (){ public Point load(Point key)throws Exception { return key; } }; –