我正在编写一个程序,需要使用一组有限的点来处理图像。我想我会将它实现为一个不可变/单例样式类。在继续构建更多关于类的复杂逻辑之前,我想得到关于核心类的意见。
import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.HashMap;
public class Point {
private final int x,y;
private final int hashCode;
private static final HashMap<int[],Point> points = new HashMap<>();
private Point(int x,int y){
this.x = x;
this.y = y;
this.hashCode = new HashCodeBuilder().append(x).append(y).toHashCode();
}
public static Point getPoint(int x,int y){
int [] candidate = new int[]{x,y};
if(points.containsKey((candidate))){
return points.get(candidate);
}
Point newPoint = new Point(x,y);
points.put(candidate, newPoint);
return newPoint;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
public int hashCode(){
return hashCode;
}
@Override
public boolean equals(Object p){
return this == p;
}
}
我将使用该类至少执行以下功能:
Point
类Point
鉴于所提供的信息,所提供的实施有哪些缺点?
注意:将项目符号列表放在代码块之前会破坏代码块的显示。错误?
答案 0 :(得分:2)
我认为你的缓存&#34;单身&#34;事情可能毫无意义。
它不会节省对象创建,因为每次请求Point时总是会创建candidate[]
。并且,除非重用Point,否则在HashMap中使用内存作为候选和 Map.Entry
。因此,非常粗略地说,除非每个Point重复使用三次次,否则您的缓存会占用更多内存。它总是使用更多的时间。
如果您没有缓存,请更改您的equals
。
P.S。其余的看起来很好,而且一成不变。您可以考虑使x和y public final
与其他Point实现更兼容。
答案 1 :(得分:1)
如果您担心被占用的内存,还有另一种方法可以解决它。
我认为你的积分尺寸有限,我建议将你的x&amp; y在一个长的变量中(如果你的尺寸是32英尺长),或者甚至是int(如果你可以在16位中适合一个尺寸),这样你就可以获得性能提升&amp;存储器中。
其他选项是使用坐标的int []数组作为一个点,虽然这会占用更多空间(因为你必须保留额外的指针引用)。
实现中的工厂方法仅适用于单线程应用程序,如果有多个线程创建点,则需要进行一些并发控制。这会占用你的资源,因为你实际上需要锁定每个点的创建。
另一个原因,为什么这个Factory方法是一个坏主意,是int []数组不重写equals和hashCode,你可以尝试创建2个具有相同内容的数组,以检查。所以你的HashMap不会简单地工作,而不是保存内存,你不仅每次都会创建一个新的Point,而且还要在你的HashMap中添加一个条目并执行不必要的计算。
因此,无论是使用Java原语,还是每次只需要创建一个新的不可变点,并使用它,不要过多地使用factoryMethods。
答案 2 :(得分:1)
你有一个正确的想法,让Point类不可变,但后来你用实例缓存复杂化了。它不是线程安全的,它会泄漏内存,因为一旦创建了一个Point,它将永远保留在hashmap中,永远不会被垃圾回收。
为什么不保持简单并定期进行无聊的价值观?您的IDE甚至会为您生成它。
然后,如果你真的真的希望拥有一个实例缓存,请使用Guava的Interner类,而不是自己滚动。结果将如下所示:
public class Point {
final int x;
final int y;
private Point(int x, int y) {
this.x = x;
this.y = y;
}
static Interner<Point> instanceCache = Interners.newWeakInterner();
public static Point of(int x, int y) {
return instanceCache.intern(new Point(x,y));
}
public int getX() { return x; }
public int getY() { return y; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point other = (Point) o;
return this.x == other.x && this.y == other.y;
}
@Override
public int hashCode() { return x * 31 + y; }
}