【Effective Java】10,javaee 架构设计与开发实践
Objects.equals(val2, that.val2);
}
@Override
public int hashCode() {
return Objects.hash(val1, val2);
}
}
这个不会有人不知道吧。网上博客应该也有一堆了。大致是如下这几个原则。
如果
a
和b
相等,那么a.equals(b)
一定为true
,则a.hashCode()
必须等于b.hashCode()
(来自于廖雪峰)如果
a
和b
不相等,那么a.equals(b)
一定为false
,则`a.hash
Code()和
b.hashCode()`尽量不要相等。(来自于廖雪峰)
hashCode
相等对象不一定相等。
因为 hashcode 其实是个映射函数,所以是有可能不同对象得到同一个值的,这时候就会用到 equals 进行比较。
hashcode 还是非常重要的,最著名的应该就是 HashMap 里面对 hash 的用法,简直牛逼。
这里,
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//低 16 与高 16 位异或,增加复杂度
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//主要就是这里,n 是 2 倍数,-1,就是从右向左全是 1,再进行上面混淆过的 hash 值与运算,自动落入范围内
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
主要就是这里tab[i = (n - 1) & hash]
主要就是这里,n 是 2 倍数,-1,就是从右向左全是 1 高位全是 0,再进行上面混淆过的 hash 值与运算,由于高位全是 0,与的结果全是 0,低位全是 1,进行与操作能保证在范围内。
由于扩容全是 2 的倍数,此时再进行比较只要把链表遍历,比较高位那个值的不同。这 hashcode 运用的,简直了。所以,hashcode 十分重要,不光是对象的标识,而且会参与运算。
这个就没啥好说的了,基本现在生成一个类,必须带上 toString,因为,大部分都是错误都是通过日志的方式,如果不覆盖就是com.mountain.monk.chapter3.Point@300ffa5d
这种形式,完全无法调试,哪个参数有问题都不知道。
Cloneable 中没有任何方法,如果一个类实现了 Cloneable 接口,Object 的 clone 方法返回该对象的逐域拷贝,如果一个类未实现 Cloneable 接口,则该对象就会抛出 CloneNotSupportedException 异常。
/**
A class implements the <code>Cloneable</code> interface to
indicate to the {@link java.lang.Object#clone()} method that it
is legal for that method to make a
field-for-field copy of instances of that class.
<p>
Invoking Object's clone method on an instance that does not implement the
<code>Cloneable</code> interface results in the exception
<code>CloneNotSupportedException</code> being thrown.
<p>
By convention, classes that implement this interface should override
<tt>Object.clone</tt> (which is protected) with a public method.
See {@link java.lang.Object#clone()} for details on overriding this
method.
<p>
Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
Therefore, it is not possible to clone an object merely by virtue of the
fact that it implements this interface. Even if the clone method is invoked
reflectively, there is no guarantee that it will succeed.
@author unascribed
@see java.lang.CloneNotSupportedException
@see java.lang.Object#clone()
@since JDK1.0
*/
public interface Cloneable {
}
clone 主要目的就是会获取一个对象的拷贝,但是和原对象不同。相当于省略了 new 一个对象,然后一个一个成员变量的 set 了。但记住它是个浅拷贝,之前有过一次经历,我想要值相同但是引用完全不同的一个对象,由于 clone 是浅拷贝,引用始终是同一个。
public class CloneA {
}
@Data
public class CloneB implements Cloneable, Serializable {
private CloneA cloneA;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
CloneB b=new CloneB();
CloneA a=new CloneA();
b.setCloneA(a);
CloneB b1=(CloneB) b.clone();
System.out.println(b1.getCloneA()==a);//true
String s=JSON.toJSONString(b);
CloneB b2= JSON.parseObject(s,CloneB.class);
System.out.println(b2.getCloneA()==a);//false
CloneB b3=new CloneB();
BeanUtils.copyProperties(b,b3);
System.out.println(b3.getCloneA()==a);//true
}
由于 clone 是浅拷贝,后面也慢慢的通过BeanUtils.copyProperties(Object,Object);
代替了,如果硬是想要 clones 深拷贝需要,内部引用对象也实现Cloneable
,然后改写下clone
方法如下所示
public class CloneA implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
@Data
public class CloneB implements Cloneable, Serializable {
private CloneA cloneA;
@Override
protected Object clone() throws CloneNotSupportedException {
评论