Java 对同一类应用不同的相等项
假设我有一个点类,它的字段是x,y,z,name。 此类的对象必须以两种不同的方式插入哈希集中,具体取决于用户选择: 等于检查x、y、z字段的相等性 等于检查x、y、z和名称字段的相等性 因此,我想知道在程序执行过程中动态组织这些equals重新定义的更好方法是什么?您可以创建两个类:Point和NamedPoint,并重写equals和hashcode方法 下面是一个伪代码示例:Java 对同一类应用不同的相等项,java,equals,hashset,Java,Equals,Hashset,假设我有一个点类,它的字段是x,y,z,name。 此类的对象必须以两种不同的方式插入哈希集中,具体取决于用户选择: 等于检查x、y、z字段的相等性 等于检查x、y、z和名称字段的相等性 因此,我想知道在程序执行过程中动态组织这些equals重新定义的更好方法是什么?您可以创建两个类:Point和NamedPoint,并重写equals和hashcode方法 下面是一个伪代码示例: class Point{ String name int x,y,z equals{
class Point{
String name
int x,y,z
equals{
...
}
hashCode{
...
}
}
class NamedPoint extends Point{
equals{
}
hashCode{
}
}
另一种选择是使用一个类,但添加一个新的布尔开关,这会更改equals和hashCode的行为
另外,我建议你阅读。您必须小心重写这些方法。使用eclipse特性Source->Generate hashCode and equals非常有用。。然后更改生成方法的行为
p.S.2:Grigory Kalabin描述了这样做可能出现的问题。您可以创建两个类:Point和NamedPoint,并重写equals和hashcode方法
下面是一个伪代码示例:
class Point{
String name
int x,y,z
equals{
...
}
hashCode{
...
}
}
class NamedPoint extends Point{
equals{
}
hashCode{
}
}
另一种选择是使用一个类,但添加一个新的布尔开关,这会更改equals和hashCode的行为
另外,我建议你阅读。您必须小心重写这些方法。使用eclipse特性Source->Generate hashCode and equals非常有用。。然后更改生成方法的行为
p.S.2:Grigory Kalabin描述了这样做可能出现的问题。如果您可以从使用哈希集更改为树集并添加自定义比较器:
public class Point implements Comparable<Point> {
private double x;
private double y;
private double z;
private String name;
public Point( final double x, final double y, final double z, final String name ) {
setX( x );
setY( y );
setZ( z );
setName( name );
}
public boolean equals( final Point point ){
final boolean isEqual =
( this.getX() == point.getX()
&& this.getY() == point.getY()
&& this.getZ() == point.getZ() )
|| ( this.getName().equals( point.getName() ) );
// System.out.println( this.toString() + " == " + point.toString() + " = " + isEqual );
return isEqual;
}
/// @return the x
public double getX() { return x; }
/// @return the y
public double getY() { return y; }
/// @return the z
public double getZ() { return z; }
/// @return the name
public String getName() { return name; }
/// @param x the x to set
public void setX(final double x) { this.x = x; }
/// @param y the y to set
public void setY(final double y) { this.y = y; }
/// @param z the z to set
public void setZ(final double z) { this.z = z; }
/// @param name the name to set
public void setName(final String name) { this.name = name; }
public String toString() {
final StringBuffer str = new StringBuffer();
str.append( '(' );
str.append( getX() );
str.append( ',' );
str.append( getY() );
str.append( ',' );
str.append( getZ() );
str.append( ',' );
str.append( getName() );
str.append( ')' );
return str.toString();
}
public double distanceFromOriginSquared(){
return this.getX()*this.getX()
+ this.getY()*this.getY()
+ this.getZ()*this.getZ();
}
@Override
public int compareTo( final Point point ) {
if ( this.getName().equals( point.getName() ) )
return 0;
final double td = this.distanceFromOriginSquared();
final double pd = point.distanceFromOriginSquared();
if ( td < pd ) return -1;
if ( td > pd ) return +1;
if ( this.getX() < point.getX() ) return -1;
if ( this.getX() > point.getX() ) return +1;
if ( this.getY() < point.getY() ) return -1;
if ( this.getY() > point.getY() ) return +1;
return 0;
}
}
因此,最后两个值不会输入到树集,因为它们被比较器拒绝。如果您可以从使用HashSet更改为树集并添加自定义比较器:
public class Point implements Comparable<Point> {
private double x;
private double y;
private double z;
private String name;
public Point( final double x, final double y, final double z, final String name ) {
setX( x );
setY( y );
setZ( z );
setName( name );
}
public boolean equals( final Point point ){
final boolean isEqual =
( this.getX() == point.getX()
&& this.getY() == point.getY()
&& this.getZ() == point.getZ() )
|| ( this.getName().equals( point.getName() ) );
// System.out.println( this.toString() + " == " + point.toString() + " = " + isEqual );
return isEqual;
}
/// @return the x
public double getX() { return x; }
/// @return the y
public double getY() { return y; }
/// @return the z
public double getZ() { return z; }
/// @return the name
public String getName() { return name; }
/// @param x the x to set
public void setX(final double x) { this.x = x; }
/// @param y the y to set
public void setY(final double y) { this.y = y; }
/// @param z the z to set
public void setZ(final double z) { this.z = z; }
/// @param name the name to set
public void setName(final String name) { this.name = name; }
public String toString() {
final StringBuffer str = new StringBuffer();
str.append( '(' );
str.append( getX() );
str.append( ',' );
str.append( getY() );
str.append( ',' );
str.append( getZ() );
str.append( ',' );
str.append( getName() );
str.append( ')' );
return str.toString();
}
public double distanceFromOriginSquared(){
return this.getX()*this.getX()
+ this.getY()*this.getY()
+ this.getZ()*this.getZ();
}
@Override
public int compareTo( final Point point ) {
if ( this.getName().equals( point.getName() ) )
return 0;
final double td = this.distanceFromOriginSquared();
final double pd = point.distanceFromOriginSquared();
if ( td < pd ) return -1;
if ( td > pd ) return +1;
if ( this.getX() < point.getX() ) return -1;
if ( this.getX() > point.getX() ) return +1;
if ( this.getY() < point.getY() ) return -1;
if ( this.getY() > point.getY() ) return +1;
return 0;
}
}
因此,最后两个值不会输入到树集中,因为它们会被比较器拒绝。一个类中不能有两个相等值。但是您可以继承一个新类并重写equals。听起来您可以使用equals和equalsWithName两个方法,也可以使用Point和NamedPoint两个类……您可以有一个子类,通过比较名称来扩展其超类的equal方法。依我看,equals应该检查所有成员。对于任何其他特定检查,您都需要手动比较这些值。@vikingsteve HashSet不会调用equalsWithName。它只能调用equals。对吧?一个班里不能有两个相等的人。但是您可以继承一个新类并重写equals。听起来您可以使用equals和equalsWithName两个方法,也可以使用Point和NamedPoint两个类……您可以有一个子类,通过比较名称来扩展其超类的equal方法。依我看,equals应该检查所有成员。对于任何其他特定检查,您都需要手动比较这些值。@vikingsteve HashSet不会调用equalsWithName。它只能调用equals。对吗?还要注意这样的层次结构可能会破坏equals的对称属性:例如,Point p.equalsanotherPoint不应该与NamedPoint p.equalsanotherPoint相同,Point.equalsanotherPoint与NamedPoint.equalspoint相同吗?还要注意这样的层次结构可能会破坏equals的对称属性:例如,点p.equalsanotherPoint不应该与命名点p.equalsanotherPoint相同,点.equalsanotherPoint不应该与命名点.equalspoint相同吗?