当前位置: 首页 > 科技观察

等于()?==?哈希码()?今天给大家科普一下

时间:2023-03-19 12:40:41 科技观察

转载本文请联系Java收藏公众号。什么时候使用关系运算符==什么时候使用u目录Java中的数据类型的equals方法?为什么equals方法会报空指针java.lang.NullPointerException?hashCode方法的作用是什么?hashCode和equals的关系?覆盖了equals方法的类,hashCode方法一定也要覆盖?java中的数据类型可以分为两大类:1.基本数据类型(原始数据类型)byte,short,char,int,long,float,double,boolean它们之间的比较,应用双等号(==),基本数据类型比较它们的值。2.引用类型(类、接口、数组)在使用(==)进行比较时,比较它们在内存中的存储地址,对象放在堆中,对象存放在栈中。(地址)。可以看出,'=='是在比较对象为引用类型时比较栈中的地址值。关系运算符==java中包含的关系运算符有小于(<)、大于(>)、小于等于(<=)、大于等于(>=)、等于(==)和不等于(!=)。==和!=适用于所有对象,但这两个运算符在比较对象时通常会出现问题:这里==和!=比较对象引用。虽然对象的内容相同,但指向对象的引用不同,所以说n1==n2是错误的。Integern1=newInteger(47);Integern2=newInteger(47);System.out.println(n1==n2);//falseSystem.out.println(n1!=n2);//这里为真==比较的是基本数据type,那么他会比较值是否相等。所以此时n1==n2输出true.intn1=100;intn2=100;System.out.println(n1==n2);//trueSystem.out.println(n1!=n2);//falseequals方法默认情况下,对象的equals方法调用Object类中的equals方法。源码如下:publicbooleanequals(Objectobj){return(this==obj);}注意这里还是用了等价==,这里比较的是引用对象,所以比较的是地址(是不是同一个对象)。第二种情况,重写了对象的equals方法。例如,String对象。源码如下:publicbooleanequals(ObjectanObject){if(this==anObject){returntrue;//如果是同一个对象,直接返回}if(anObjectinstanceofString){//是String对象开始判断content.StringanotherString=(String)anObject;intn=value.length;if(n==anotherString.value.length){charv1[]=value;charv2[]=anotherString.value;inti=0;while(n--!=0){//逐个字符比较,如果有不相等的字符,则返回falseif(v1[i]!=v2[i])returnfalse;i++;}returntrue;}}returnfalse;}此时,重写equals方法的实现不同,但是重写后一般是通过对象的内容是否相等来判断对象是否相等,对于大多数Java类库来说,实现equals()方法来比较对象的内容对象,而不是比较对象的引用。避免equals方法报空指针,避免equals方法报空指针。让我先告诉你。答案是使用Objects.equals(a,b),JDK7中增加了一个Objects工具类,提供了一些操作对象的方法。它由一些静态实用方法组成。这些方法是null-save(空指针安全)或null-tolerant(Tolerantofnullpointers),用于计算对象的hashcode,返回对象的字符串表示,比较两个对象。默认情况下,不重写对象的equals方法。调用Object类中的equals方法。报错示例:aa=null;//假设接收到config对象,不知道是否为空,所以比较booleanr=a.equals(newB());System.out.println(r);//输出java.lang.NullPointerException这时候由于我们的疏忽,在接收到参数后,没有对参数进行校验,导致调用equals方法报空指针。//其他例子有:null.equals("javabook");//NullPointerException"javacollection".equals(null);//false只有当equals左边的对象不为Null时,才有结果null.equals(null);//NullPointerException使用Objects.equals(a,b),两边都是Null,不会报空指针Objects.equals(null,"javabook");//falseObjects.equals("javabook",null);//falseObjects.equals(null,null);//true看一下Objects.equals方法的源码,就是一个publicstaticbooleanequals(Objecta,Objectb){return(a==b)||(a!=null&&a.equals(b));}容忍null的hashCode()方法指针哈希(Hash)实际上是一个人的名字。由于他提出了哈希算法的概念,因此以他的名字命名。哈希算法,又称散列算法,是指按照特定的算法,将数据直接分配给一个地址。流行的理解是一种从任何类型的数据中创建小型数字“指纹”的方法。在java中,默认情况下,对象不会覆盖hashCode()方法。它使用了Object类中的.publicnativeinthashCode();//它是一个native方法。Object类定义的hashCode方法会为不同的对象返回不同的值一个整数。(这是通过将对象的内部地址转换为整数来实现的)示例:Configconfig1=newConfig();Configconfig2=newConfig();System.out.println(config1.hashCode());//1128032093System.out.println(config2.hashCode());//1066516207System.out.println(config1.equals(config2));//falsehashCode和equals的关系是Object类中的方法,因为Object类属于所有类的基类,因此这两个方法可以在所有类中被覆盖。原则一:如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等;原则2:如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等也可能不相等;原则3:如果x和y的hashCode()不相等,那么x.equals(y)必须返回“false”;原则4:equals方法一般是为用户调用的,hashcode方法一般不被用户调用;原则5:当一个对象类型作为一个集合对象的元素时,那么这个对象应该有自己的equals()和hashCode()设计,并且必须遵守上述几个原则。在Java应用程序的执行期间,对同一对象的hashCode方法的多次调用必须一致地返回相同的整数,前提是用于等于对象的信息没有被修改。从一个应用程序的一次执行到同一应用程序的另一次执行,该整数不需要保持一致。如果根据equals(Object)方法两个对象相等,则对这两个对象中的每一个调用hashCode方法必须产生相同的整数结果。如果根据equals(java.lang.Object)方法两个对象不相等,则不需要对任一对象调用hashCode方法来生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可以提高哈希表的性能。为什么必须在每个覆盖equals方法的类中覆盖hashCode方法?在每个覆盖equals方法的类中,hashCode方法也必须被覆盖。如果不这样做,就会违反Object.hashCode的一般约定,这将导致该类无法与所有基于散列的集合一起正常工作。上面我们介绍了什么是hashCode。要想进一步了解hashCode的应用,首先要了解Java中的Container,因为HashCode只有在需要使用哈希算法的数据结构中才有用,比如HashSet,HashMap。。我们以hashMap为例:HashMap是一种存储数据的结构由数组和链表组成。判断一个数据存放在数组的哪个位置,就是通过hashCode方法计算存放的位置。如果有冲突,会调用equals方法进行比较。如果不同,则将其添加到链表的末尾。如果相同,则原件将被替换。数据。当然计算位置不是通过上面简单的hashCode方法计算出来的。中间还有一些其他的步骤。这里可以简单的认为hashCode决定位置。代码如下:publicVput(Kkey,Vvalue){//如果哈希表没有初始化则初始化if(table==EMPTY_TABLE){//初始化哈希表inflateTable(threshold);}//当key为null,调用putForNullKey方法,将null保存在表的第一个位置。这是HashMap允许null的原因key的值和数组的长度Slotinti=indexFor(hash,table.length);//获取存储位置的表项,如果表项不为空,则遍历表项所在的链表for(Entrye=table[i];e!=null;e=e.next){Objectk;//通过key的hashCode和equals方法判断key是否存在。如果存在,则用新值替换旧值并返回旧值if(e.hash==hash&&((k=e.key)==key||key.equals(k))){VoldValue=e.value;e.value=value;e.recordAccess(this);returnoldValue;}}//修改次数加1modCount++;//如果找不到链表或者遍历链表后找到判断key不存在,则新建一个Entry加入到HashMap中根据传入的元素hashCode方法的返回值与特定值异或:staticintindexFor(inth,intlength){//对hash值和length-1进行AND运算计算索引returnh&(length-1);}回到我们的问题:为什么每个重写equals方法的类,您还必须重写hashCode方法吗?如果重写equals,但是hashCode的实现没有重写,那么类的hashcode方法就是Object默认的hashcode方法,因为默认的hashcode方法是根据对象的内存地址通过hash算法得到一个值,那么很可能有两个对象明明“相等”,但hashCode却不一样。这样,当你用其中一个作为key保存在hashMap,hasoTable或者hashSet中,然后用“equal”去查找另一个的时候,当你把它们作为key值来查找的时候,你根本就找不到了。导致HashSet和HashMap无法正常工作。比如:有一个A类重写了equals方法,但是没有重写hashCode方法。对象a1和对象a2使用equals方法相等。根据上面hashcode的用法,那么他们两个的hashcode一定是相等的,但是这里因为没有重写hashcode的方法,所以两个hashcode是不一样的。因此,在重写equals方法之后,我们尝试将hashcode方法也重写,通过一定的算法让它们相等于equals。,也将具有相同的哈希码值。总结==比较基本数据类型时,比较的是值==比较引用数据类型时,比较的是对象的引用地址对象的equals方法。就是对象引用地址对象的equals方法。改写后用于比较对象内容是否相等。实现可以由IDE生成或自定义。(比如重写String类的equals方法就是对字符一个一个进行比较。)不重写,对象的equals方法调用了Object类中的equals方法。当条件左边为Null时,会报空指针。使用Objects.equals(a,b)避免系统使用空指针hashcode重写用于快速检索对象的equals方法后,hashcode方法也必须重写,否则会导致HashSet、HashMap等容器依赖hashCode出故障