前言:
现时朋友们对“java通用方法”都比较注意,同学们都需要了解一些“java通用方法”的相关内容。那么小编同时在网摘上收集了一些关于“java通用方法””的相关文章,希望姐妹们能喜欢,咱们一起来学习一下吧!本文主要讲JAVA中的通用方法规约。内容主要取自JDK源码注释和Effective Java(作者是Joshua Bloch大神,jdk中的集合java.util.Collection, java.util.Map等就是他的杰作,如果对java性能优化方面感兴趣的同学建议读一下这本书)。
java中Object的equals,hashcode,clone,toString方法,Comparable.compareTo方法应该遵从一定的规约,这有利于数据的存取、格式化、排序等,关于这些方法的规约在JDK源码注释中都有描述。
你面试时是否有人问你Object的hashcode方法返回的是什么?
HashMap中数据的存取原理?
如何降低哈希冲突的概率 ?
假如有个javaBean里面有两个关键字段userGroupId和userId那么应该如何实现其hashcode方法和equals方法?
Double、String、数组的hashcode是如何实现的?
对于刚入门java的同学被问到这样的问题时是否曾一脸懵逼?哈哈!开个玩笑,下面步入正题。
1. Object.equals(Object)
equals方法用于判断某个实例是否与当前实例逻辑相等。
无需重写equals的场景:
1) 类的每个实例本身是唯一的:如Thread,Enum
2) 父类已经重写了equals方法,并且该equals方法适用于子类。如AbstractList,AbstractMap等。
3) 无需判断逻辑相等。如java.util.Collections,只提供方法,不提供数据。
equals方法规约:
1) 自反性(reflexive):对于任何非null的引用值x,x.equals(x)必须返回true。
2) 对称性(symmetric):对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。
3) 传递性(transitive):对于任何非null的引用值x,y和z,如果x.equals(y)返回true,且y.equals(z)返回true,那么x.equals(z)也必须返回true。
4) 一致性(consistent):对于任何非null的引用值x和y,只有equals的比较操作在实例中所用的信息没有被修改,多次调用x.equals(y)总会一致地返回相同的结果。
5) 非空性(Non-nullity):对于任何非null的引用值x,x.equals(null)必须返回false。
JDK equals实现参考:
String.equals(Object) //比较实例->比较字符串长度->遍历char[]逐个比较
Date.equals(Object) //比较毫秒数
Arrays.equals(Object[],Object[]) //比较实例->比较数组长度->遍历数组逐个比较
2. Object.hashCode()
hashcode方法返回实例的哈希码,用于支持散列表如HashMap等。默认实现是将实例的内部地址转化为int值。
hash(散列)可以理解为让数据有规则的分散开来。为何要分散开?假设HashMap中很多Key的hashcode相同,这时map中会存在一个链表特别长,如果要查询map中哈希冲突的key对应的value,最坏的情况下要把这个特别长的链表全部遍历,这样会严重影响map的性能。如何你的hashcode方法设计的足够巧妙,使得map中的数据均匀的散列在各个链表中,那么这个map的性能是比较高的。
hashcode方法规约:
1) 同一实例上多次调用hashCode方法必须返回相同的int值。
2) 如果objectA.equals(objectB)为真,则objectA.hashcode()应该等于objectB.hashcode()。
3) 如果objectA.equals(objectB)为假,则不要求objectA.hashcode()等于objectB.hashcode()。但是为不同的实例生成不同的hashcode可提高HashMap等容器的性能。
常见数据类型hash算法:
如果需要覆盖普通类的equals与hashcode方法,可以使用IDE自带的代码生成工具:
idea: Code -> Generate.. -> equals and hashcode -> 选择关键字段
3. Object.clone()
创建并返回当前实例的副本。
clone方法规约:
1) 对于任意实例x,x.clone() != x
2) 对于任意实例x,x.clone().equals(x)
注意:Object.clone()是protected方法,要实现克隆必须重写该方法并实现Cloneable(空接口,仅作标识),否则会抛出CloneNotSupportedException。
4. Comparable.compareTo(T)
实现了Comparable接口的类的实例可互相比较大小,compareTo方法返回负整数、0、正整数对应于当前实例小于、等于、大于指定实例。
该方法用于数组或集合元素的排序,如:
java.util.Arrays.sort(Object[]) (该方法在排序时会将数组元素强制转换为Comparable,如果没有实现Comparable则抛出类型转换异常);
java.util.Collections
<T extends Comparable<? super T>> void sort(List<T> list)
compareTo方法规约:
1) x.compareTo(y) == y.compareTo(x),如果x.compareTo(y)抛出异常则y.compareTo(x)也应该抛出异常
2) 传递性:如果(x.compareTo(y)>0 && y.compareTo(z)>0)为真,则x.compareTo(z)>0也为真
3) 如果x.compareTo(y)==0 则x.compareTo(z) == y.compareTo(z)
4) 强烈推荐但非必须,x.compareTo(y)==0) == (x.equals(y))
与Comparable功能相似的接口有Comparator,区别是前者需要在类内部实现Comparable接口,而Comparator通常是作为函数式接口(@FunctionalInterface)使用。
5. Object.toString()
返回当前实例的String表示格式。
Object的toString方法返回格式为:className + '@'+ 十六进制hashcode,即:
getClass().getName() + '@' + Integer.toHexString(hashCode())
toString返回的String应该是简单明了、易于阅读的实例表示法。对于需要打印对象信息的类应当重写此方法。
标签: #java通用方法