2011-11-23 66 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; } }; –