写点什么

【Effective Java】10,javaee 架构设计与开发实践

用户头像
极客good
关注
发布于: 刚刚

Objects.equals(val2, that.val2);


}


@Override


public int hashCode() {


return Objects.hash(val1, val2);


}


}


11.覆盖 equals 时总要覆盖 hash Code




这个不会有人不知道吧。网上博客应该也有一堆了。大致是如下这几个原则。


  • 如果ab相等,那么a.equals(b)一定为true,则a.hashCode()必须等于b.hashCode()(来自于廖雪峰)

  • 如果ab不相等,那么a.equals(b)一定为false,则`a.hash


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


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 十分重要,不光是对象的标识,而且会参与运算。


12.始终要覆盖 toString




这个就没啥好说的了,基本现在生成一个类,必须带上 toString,因为,大部分都是错误都是通过日志的方式,如果不覆盖就是com.mountain.monk.chapter3.Point@300ffa5d这种形式,完全无法调试,哪个参数有问题都不知道。


13.谨慎覆盖 clone




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 {

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
【Effective Java】10,javaee架构设计与开发实践