Java 除了比较两个对象的相等性,还有什么替代方法?
事实证明,定义equals() 不是琐碎的;事实上,这是适度的 很难做到正确,尤其是在 子类的情况。最好的 对这些问题的处理正在进行中 霍斯特曼的核心Java第1卷 如果必须始终重写equals(),那么,有什么好方法可以避免被迫进行对象比较呢?哪些是好的“设计”备选方案 编辑: 我不确定这是否是我的初衷。也许这个问题应该更接近于“你为什么要比较两个物体?”根据你对这个问题的回答,有没有替代方案来进行比较?我不是说,平等的不同实现。我的意思是,根本不使用平等。我认为关键点是从这个问题开始,你为什么要比较两个物体。Mmhh 在某些情况下,可以使对象不可修改(只读),并从单个点创建它(工厂方法) 如果需要两个具有相同输入数据(创建参数)的对象,工厂将返回相同的实例引用,然后使用“==”就足够了 这种方法仅在某些情况下有用。而且大多数时候看起来都太过分了 看一看就知道如何实现这样的事情 警告:代码太多了 简而言之,请参见包装器类的工作原理 这是真的Java 除了比较两个对象的相等性,还有什么替代方法?,java,equals,Java,Equals,事实证明,定义equals() 不是琐碎的;事实上,这是适度的 很难做到正确,尤其是在 子类的情况。最好的 对这些问题的处理正在进行中 霍斯特曼的核心Java第1卷 如果必须始终重写equals(),那么,有什么好方法可以避免被迫进行对象比较呢?哪些是好的“设计”备选方案 编辑: 我不确定这是否是我的初衷。也许这个问题应该更接近于“你为什么要比较两个物体?”根据你对这个问题的回答,有没有替代方案来进行比较?我不是说,平等的不同实现。我的意思是,根本不使用平等。我认为关键点是从这个问题开始,你为什
new Integer( 2 ) == new Integer( 2 )
这是错误的
它在内部保留引用,如果输入值相同,则返回引用
正如您所知,整数是只读的
类似的情况也发生在这个问题所涉及的String类中。如何正确处理它 这是我的equals模板,它是Josh Bloch从有效Java应用的知识。阅读本书了解更多详细信息:
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
// only do this if you are a subclass and care about equals of parent
if(!super.equals(obj)) {
return false;
}
if(obj == null || getClass() != obj.getClass()) {
return false;
}
final YourTypeHere other = (YourTypeHere) obj;
if(!instanceMember1.equals(other.instanceMember1)) {
return false;
}
... rest of instanceMembers in same pattern as above....
return true;
}
我认为平等不应该总是被忽视。我理解的规则是,只有在清楚如何定义语义等价的对象的情况下,重写equals才有意义。在这种情况下,还可以重写hashCode(),这样就不会有定义为等价的对象返回不同的hashCode
如果你不能定义有意义的等价,我看不出有什么好处 也许我没有抓住要点,但是使用equals而不是用不同的名称定义自己的方法的唯一原因是因为许多集合(可能还有JDK中的其他东西,或者现在叫什么)都希望equals方法定义一致的结果。但除此之外,我可以想到三种你想在同等条件下进行的比较:
所有这些信息都来自()。关于这一点的第一版章节仍然是免费的 来自有效Java: 避免问题的最简单方法是 在中,不重写equals方法 在这种情况下,类的每个实例 它只与自身相等 任意重写equals/hashCode的问题是继承。一些equals实现提倡这样测试:
if (this.getClass() != other.getClass()) {
return false; //inequal
}
事实上,(3.4)Java编辑器在您使用源工具生成方法时就是这样做的。根据布洛赫的说法,这是一个错误,因为它违反了法律
来自有效Java:
没有办法延长期限
实例化类并添加一个值
保持相等时的分量
合同
类和接口一章中介绍了两种最小化相等问题的方法:
就我所见,唯一的替代方法是在类外部的形式中测试相等性,如何执行取决于类型的设计和您试图在其中使用它的上下文 例如,您可以定义一个接口来记录如何对其进行比较。在下面的代码中,服务实例可能在运行时被同一类的较新版本所替换-在这种情况下,如果有不同的类加载器,equals比较将始终返回false,因此重写equals/hashCode将是多余的
public class Services {
private static Map<String, Service> SERVICES = new HashMap<String, Service>();
static interface Service {
/** Services with the same name are considered equivalent */
public String getName();
}
public static synchronized void installService(Service service) {
SERVICES.put(service.getName(), service);
}
public static synchronized Service lookup(String name) {
return SERVICES.get(name);
}
}
公共类服务{
私有静态映射服务=newhashmap();
静态接口服务{
/**具有相同名称的服务被认为是等效的*/
公共字符串getName();
}
公共静态同步无效安装服务(服务服务){
SERVICES.put(service.getName(),service);
}
公共静态同步服务查找(字符串名称){
return SERVICES.get(名称);
}
}
“为什么要比较两个对象?” 一个明显的例子是测试两个字符串
public class Services {
private static Map<String, Service> SERVICES = new HashMap<String, Service>();
static interface Service {
/** Services with the same name are considered equivalent */
public String getName();
}
public static synchronized void installService(Service service) {
SERVICES.put(service.getName(), service);
}
public static synchronized Service lookup(String name) {
return SERVICES.get(name);
}
}
Adding duplicates to a map (bad):
Result of map.get(bean1):first
Result of map.get(bean2):second
Result of map.get(new NameBean("Alice"): null
Adding duplicates to a map (good):
Result of map.get(bean1):second
Result of map.get(bean2):second
Result of map.get(new ImprovedNameBean("Alice"): second
// This bean cannot safely be used as a key in a Map
public class NameBean {
private String name;
public NameBean() {
}
public NameBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
// This bean can safely be used as a key in a Map
public class ImprovedNameBean extends NameBean {
public ImprovedNameBean(String name) {
super(name);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if(obj == null || getClass() != obj.getClass()) {
return false;
}
return this.getName().equals(((ImprovedNameBean)obj).getName());
}
@Override
public int hashCode() {
return getName().hashCode();
}
}
public class MapDuplicateTest {
public static void main(String[] args) {
MapDuplicateTest test = new MapDuplicateTest();
System.out.println("Adding duplicates to a map (bad):");
test.withDuplicates();
System.out.println("\nAdding duplicates to a map (good):");
test.withoutDuplicates();
}
public void withDuplicates() {
NameBean bean1 = new NameBean("Alice");
NameBean bean2 = new NameBean("Alice");
java.util.Map<NameBean, String> map
= new java.util.HashMap<NameBean, String>();
map.put(bean1, "first");
map.put(bean2, "second");
System.out.println("Result of map.get(bean1):"+map.get(bean1));
System.out.println("Result of map.get(bean2):"+map.get(bean2));
System.out.println("Result of map.get(new NameBean(\"Alice\"): "
+ map.get(new NameBean("Alice")));
}
public void withoutDuplicates() {
ImprovedNameBean bean1 = new ImprovedNameBean("Alice");
ImprovedNameBean bean2 = new ImprovedNameBean("Alice");
java.util.Map<ImprovedNameBean, String> map
= new java.util.HashMap<ImprovedNameBean, String>();
map.put(bean1, "first");
map.put(bean2, "second");
System.out.println("Result of map.get(bean1):"+map.get(bean1));
System.out.println("Result of map.get(bean2):"+map.get(bean2));
System.out.println("Result of map.get(new ImprovedNameBean(\"Alice\"): "
+ map.get(new ImprovedNameBean("Alice")));
}
}