什么问题/陷阱,必须重写时,必须考虑equals和hashCode?
我有一个使用switch case for instanceofobject的问题:
例如:我的问题可以用Java重现:
if(this instanceof A)
doA();
else if(this instanceof B)
doB();
else if(this instanceof C)
doC():
Run Code Online (Sandbox Code Playgroud)
如何使用switch...case?
当使用getClass()和==运算符over instanceOf运算符时,我看到了性能的提升.
Object str = new Integer("2000");
long starttime = System.nanoTime();
if(str instanceof String) {
System.out.println("its string");
} else {
if (str instanceof Integer) {
System.out.println("its integer");
}
}
System.out.println((System.nanoTime()-starttime));
starttime = System.nanoTime();
if(str.getClass() == String.class) {
System.out.println("its string in equals");
} else {
if(str.getClass() == Integer.class) {
System.out.println("its integer");
}
}
System.out.println((System.nanoTime()-starttime));
Run Code Online (Sandbox Code Playgroud)
是否有任何准则,哪一个使用getClass()或instanceOf?
给定一个情景:我知道要匹配精确类,即String,Integer(这些都是final类)等.
使用instanceOf运算符不好的做法?
我正在尝试编写一些通用代码来定义基于字段列表的类相等和哈希码.在编写我的equals方法时,我想知道,基于Java约定,两个不同的对象是否应该是相同的.让我举几个例子;
class A {
int foo;
}
class B {
int foo;
}
class C extends A {
int bar;
}
class D extends A {
void doStuff() { }
}
...
A a = new A(); a.foo = 1;
B b = new B(); b.foo = 1;
C c = new C(); c.foo = 1; c.bar = 2;
D d = new D(); d.foo = 1;
a.equals(b); //Should return false, obviously
a.equals(c);
c.equals(a); //These two must be the same …Run Code Online (Sandbox Code Playgroud) 我对java很新,我只是想了解@Override一下这些equals()和hashcode()方法.
我知道equals方法要正确,它需要:
a.equals(a)a.equals(b) 然后 b.equals(a)a.equals(b) && b.equals(c) 然后 a.equals(c) ! a.equals(null)我在努力确定上述属性中的哪一个并且在编写equals方法的上面时并不满意.
我知道eclipse可以为我生成这些,但是因为我还没有完全理解这个概念,所以写出来可以帮助我学习.
我已经写出了我认为正确的方法,但是当我查看eclipse生成的版本时,我似乎"缺少"某些方面.
例:
public class People {
private Name first; //Invariants --> !Null, !=last
private Name last; // !Null, !=first
private int age; // !Null, ! <=0
...
}
Run Code Online (Sandbox Code Playgroud)
我写的:
public boolean equals(Object obj){
if (obj == null){
return false;
}
if (!(obj instanceof People)){
return false;
}
People other = (People) obj;
if (this.age != …Run Code Online (Sandbox Code Playgroud) 它在Object的.equals(Object)javadoc中声明:
它是对称的:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true.
在示例代码中几乎无处不在,我看到覆盖的.equals(Object)方法,它instanceof用作第一个测试之一,例如:在重写equals和hashCode时必须考虑哪些问题/陷阱?
public class Person {
private String name;
private int age;
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (!(obj instanceof Person))
return false;
...
}
Run Code Online (Sandbox Code Playgroud)
}
现在,随着class SpecialPerson extends Person具有equals:
if (!(obj instanceof SpecialPerson))
return false;
Run Code Online (Sandbox Code Playgroud)
我们不保证.equals()是对称的.这里已经讨论过这样的例子:任何理由偏好getclass-over-instanceof-when-generating-equals
Person a = new Person(), b = new SpecialPerson();
a.equals(b); //sometimes true, since b instanceof Person …Run Code Online (Sandbox Code Playgroud) 我经常使用Eclipse的代码生成工具(Source/Generate hashCode()和equals()...)来为简单的POJO类创建equals()实现.如果我选择"使用instanceof来比较类型",则会生成类似于此的equals()实现:
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof MyClass)) {
return false;
}
MyClass other = (MyClass) obj;
// check the relevant fields for equality
}
Run Code Online (Sandbox Code Playgroud)
今天一位同事指出,第二个if语句根本不是必需的,因为只要obj为null,类型检查的instanceof就会返回false.(见问题3328138.)
现在,我想那些为Eclipse JDT编写代码模板的人也值得他们的盐.所以我认为这个空检查必须有一些原因,但我不确定它是什么?
(还有问题7570764可能会给出一个提示:如果我们使用getClass()比较进行类型检查而不是instanceof,obj.getClass()不是null安全.如果我们使用instanceof,可能代码模板不够聪明,不能忽略null检查.)
编辑:Dragan在他的回答中注意到,类型检查的instanceof不是Eclipse中的默认设置,所以我编辑了这个问题.但这并没有改变任何事情.
另外请不要建议我使用getClass()或(甚至更好!)一个不同的IDE.这不是重点,不能回答这个问题.我没有询问有关如何编写equals()实现的建议,无论是使用instanceof还是getClass()等.
问题大致是:这是Eclipse中的一个小错误吗?如果不是,那为什么它有资格成为一个功能?
在阅读之后(再次,应该已经做了很久以前)正确实现equals和hashcode我得出了这些结论,这对我有用:
如果在JDK 7之前:首选使用Apache commons equalsbuilder和hashcodebuilder.(或番石榴).他们的javadoc包含如何以良好方式使用它们的示例.
如果是JDK 7 ++:使用新的Objects实用程序类
但是,如果为hibernate编写一些特殊的请求出现(参见更远的源代码)其中推荐使用instanceof而不是getClass,因为hibernate创建了延迟加载的子类的代理.
但据我所知,如果这样做又发生了另一个潜在的问题:使用getClass的原因是为了确保equals合约的对称属性.JavaDoc中:
*It is symmetric: for any non-null reference values x and y, x.equals(y)
should return true if and only if y.equals(x) returns true.*
Run Code Online (Sandbox Code Playgroud)
通过使用instanceof,它可能不是对称的.示例:B扩展A. A的等于A的检查实例.B的等于B的实例检查.给A a和B b:
a.equals(b) - > true b.equals(a) - > false
如何实现与hibernate相等而不会失去对称属性的风险?使用getClass时我似乎不安全,使用instanceof时我不安全?
答案是永远不要将重要成员添加到子类,然后使用instanceof是安全的(对于hibernate)?
我读到的消息来源:
在Java中覆盖equals和hashCode时应该考虑哪些问题?
Josh Blochs的第7和第8项优秀书籍"Effective Java",http: //web.archive.org/web/20110622072109/http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf
关于Java 7:http://www.javacodegeeks.com/2012/11/guavas-objects-class-equals-hashcode-and-tostring.html
我知道getClass()方法java.lang.Object.但在我的申请中,我知道我的所有课程.那么,使用这种方法的实际目的是什么?
我需要为MyClas制作equals函数.
public class MyClass
{
boolean equals(Object value)
{
if (... value is type of MyCLass ...)
{
return= ... check conditions...;
} else return false;
}
}
Run Code Online (Sandbox Code Playgroud)
为此,我需要知道Object的值是否是MyClass的类型.怎么做?
java ×10
instanceof ×5
equals ×4
class ×2
hashcode ×2
eclipse ×1
eclipse-jdt ×1
hibernate ×1
java-7 ×1
oop ×1
overriding ×1