【发布时间】:2014-01-13 16:37:06
【问题描述】:
代码:
public class FeatureBuilder implements IFeatureBuilder {
private final Map< java.awt.Shape, ShapeAttributes > shapes = new HashMap<>();
[...]
@Override
public void addToContainer( java.awt.Shape shape ) {
System.err.println( shape.getClass());
shapes.put( shape, new ShapeAttributes( ... ));
}
@Override
public void removeFromContainer( double x, double y ) {
final Set< Shape > rm = new HashSet<>();
final Point2D loc = new Point2D.Double( x, y );
for( final Shape shape : shapes.keySet()) {
if( shape.contains( loc )) {
System.err.println( "shapes.containsKey( shape ): " +
shapes.containsKey( shape ));
rm.add( shape );
}
}
System.err.println( "cardinality before removal : " + shapes.size());
shapes.keySet().removeAll( rm );
System.err.println( "cardinality after removal : " + shapes.size());
}
输出:
class java.awt.geom.Rectangle2D$Double
shapes.containsKey( shape ): false <<<<<<< This is unexpected!
cardinality before removal : 1
rm cardinality : 1
cardinality after removal : 1
我很惊讶:for 迭代器在Map.keySet() 上检索到的实例不是Map 中的键!
这怎么可能?
此方法的主要错误是放置在rm 中的选定Shape 实例不会从shapes 中删除。
阅读您的答案后,代码变为:
public class DecoratedShape {
public final Shape _shape;
public /* */ Color _stroke = Color.BLACK;
public /* */ float _strokeWidth = 3.0f;
public /* */ Color _fill = Color.BLACK;
public DecoratedShape( Shape shape, Color stroke, float strokeWidth, Color fill ) {
_shape = shape;
_stroke = stroke;
_strokeWidth = strokeWidth;
_fill = fill;
}
public boolean contains( Point2D loc ) {
return _shape.contains( loc );
}
public void paint( Graphics2D g ) {
g.setStroke( new BasicStroke( _strokeWidth ));
g.setColor( _fill );
g.fill( _shape );
g.setColor( _stroke );
g.draw( _shape );
}
}
public class FeatureBuilder implements IFeatureBuilder {
private final List< DecoratedShape > _shapes = new LinkedList<>();
[...]
@Override
public void addToContainer( Object o ) {
_shapes.add( new DecoratedShape((Shape)o, _stroke, _strokeWidth, _fill ));
}
@Override
public void removeFromContainer( double x, double y ) {
final Set<DecoratedShape> rm = new HashSet<>();
final Point2D loc = new Point2D.Double( x, y );
for( final DecoratedShape shape : _shapes ){
if( shape.contains( loc ) ){
rm.add( shape );
}
}
_shapes.removeAll( rm );
}
public void paint( Graphics2D g ) {
for( final DecoratedShape shape : _shapes ) {
shape.paint( g );
}
}
}
现在,它按预期工作......非常感谢!
【问题讨论】:
-
这通常发生在equals和hashcode方法不一致的时候。但是,
Rectangle2D... 似乎并非如此 -
你能给出一个 SSCCE(即创建一个重现行为的 Rectangle2D.Double 实例)吗?
-
也许一些更多的调试信息,例如打印出
hashcode()将有助于比较两者以及equals()是否返回true。 -
首先,您不应该在
HashMap中使用可变对象作为键。我想这就是在这里造成问题的原因。但是我们需要更多的代码来破解它。 -
@Aubin 您可以扩展您感兴趣的形状,并给它们一个在调整大小时不会改变的名称或 ID。或者更好的是,定义您自己的
ShapeHolder,而不是使用形状和字符串/整数 id。然后,您可以使用该 ID 作为地图的键。否则这将是一个棘手的练习。
标签: java collections map awt