==与equal的区别

来源:互联网 发布:软件研发管理体系 编辑:程序博客网 时间:2024/05/17 07:09

1、java中的数据类型

  • 基本类型:如:int、short、long、float、double、boolean
  • 引用类型
  • null类型:这是一个非常特殊的类型

2、基本类型之间的比较

大家都知道基本之间的类型比较不能用equal,而是用==,那么用==是怎么比较大小的呢?我们就来探一个究竟。

在计算机中,所有储存的东西都是用二进制来表示的,例如:01010101010101,那么基本类型在计算机中肯定是用二进制表示的吧,但是数据储存是有一定格式的,不同的类型数据的格式是不一样的,下面介绍几种数据类型的储存格式。

  • boolean 类型

在java中,boolean是用一字节表示的,由于boolean 只有两个值,即0和1,用二进制表示就是为00000000和00000001

  • int类型

在java中,int是用32位来储存的,而且是有符号的。下面就说一个例子:

比如说:100 在java中,表示为:00000000000000000000000001100100  而-100在java中,表示为:11111111111111111111111110011100

如果不知道把100和-100怎么转成这样二进制的话,那你就得先百度一下了,先学学这个知识了,因为我这里是总结==而不是进制之间的转换,在这里就细说了。

现在我们已经把他们都转化为二进制了,这个时候可以开始比较了,在内存中,他们会一位一位地比较,很显然,他们不相等。整数之间的比较非常简单,接下来是float类型的比较了。

  • float类型

先明确float类型在计算机中是怎么被存储起来的,下面是介绍(下面这段介绍性文字是引用另外一位高人的):

根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式:

  V = (-1)^s×M×2^E
  (1)(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
  (2)M表示有效数字,大于等于1,小于2。
  (3)2^E表示指数位。
  举例来说,十进制的5.0,写成二进制是101.0,相当于1.01×2^2。那么,按照上面V的格式,可以得出s=0,M=1.01,E=2。
  十进制的-5.0,写成二进制是-101.0,相当于-1.01×2^2。那么,s=1,M=1.01,E=2。
  IEEE 754规定,对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
 
  对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
 

5.
  IEEE 754对有效数字M和指数E,还有一些特别规定。
  前面说过,1≤M<2,也就是说,M可以写成1.xxxxxx的形式,其中xxxxxx表示小数部分。IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。
  至于指数E,情况就比较复杂。
  首先,E为一个无符号整数(unsigned int)。这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,E的真实值必须再减去一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。
  比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
  然后,指数E还可以再分成三种情况:
  (1)E不全为0或不全为1。这时,浮点数就采用上面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。
  (2)E全为0。这时,浮点数的指数E等于1-127(或者1-1023),有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
  (3)E全为1。这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);如果有效数字M不全为0,表示这个数不是一个数(NaN)。

说完原理以后,接下来我就举一例子

1.00000000和1.000000001

按照上面的规则,1.00000000转化为 V = (-1)^s×M×2^E这种形式:1.0*2^0,转化为二进制就是:0 01111111 00000000000000000000000

而1.000000001转化为V = (-1)^s×M×2^E这种形式:1.0*2^0,转化为二进制就是:0 01111111 00000000000000000000000

按照这种情况对比,可以得出1.00000000与1.000000001是相等的,对他们就是相等的。但是如果是64bit的时候就是不是相等的,这个你可以试一试。

  • double类型

double类型的比较跟float类型的比较其实是一样的,只不过是把精度提高了,用的是64位,比如说:1.00000000和1.000000001的比较

1.00000000转化为二进制为0 01111111    0000000000000000000000000000000000000000000000000000

而1.000000001转化为二进制为0 01111111111 0000000000000000000000000000010001001011100000101111

很显然这两个数字是不相等的。

在float类型的比较,我们会用Float.floatToIntbit(float value)这个函数来比较两个浮点数的大小,那么用Float.floatToInbit(float value)与用==来比较两个浮点数有什么不同呢?Float.floatToInbit(float value)的原理是怎么样的呢?

先介绍Float.floatToInbit(float value)的原理:

官方文档是这样说的:Returns a representation of the specified floating-point value according to the IEEE 754 floating-point "single format" bit layout

举个例子来说吧:

比如说:float a=1.00000000;  Float.floatToIntbit(a)=1065353216,这是怎么来的呢?原来是这样的,把1.00000000按照V = (-1)^s×M×2^E这个规则转成二进制就是:0 01111111 00000000000000000000000,接着把这个二进制转化为整数就是:1065353216了。

用Float.floatToIntbit(float value)跟用==来比较两个浮点数的大小有什么不同呢?

对与一般的浮点数,用两种方法都一样。主要不同的地方就是比较特殊的数,

NaN、-0.0 、 0.0

用==来比较就是 NaN==NaN是false     -0.0==0.0是true

用Float.floatToIntbit()来比较就是  Float.floatToIntbit(NaN)==Float.floatToIntbit(NaN)是true,而Float.floatToIntbit(0.0)==Float.floatToIntbit(-0.0)是false这个得解释一下,为什么会出现这样的差别呢?

什么是NaN:她是指not a number,不是一个数,比如说1.0/0.0是多少呢,我们定义这样的数为NaN。对于oo来说,这就是我们定义的一个对象,所以Float.floatToIntbit(NaN)==Float.floatToIntbit(NaN)就是true了,在这个函数里面NaN是对应一个整数的,查看jdk源码或者jdk文档就知道了。从数学的角度来说:NaN==NaN是false,因为不是一个数怎么能跟不是一个数相等呢?0.0和-0.0的问题是比较好解析的,从数学的角度来说-0.0与0.0是相等的,但是 Float.floatToIntbit(-0.0)根据上面的规则就是2147483648  而Float.floatToIntbit(0.0)是0,所以很显然不相等。详情请看这里

那么我们在编程中,一般用哪一个来进行比较呢?是用==好呢?还是用Float.floatToIntbit()这个好呢?这个就要看具体情况了,我现在也不知道用他们的一般规则

double之间的比较这里就不重复了,原理跟float一样。

3、对象之间的比较

我们在做面试题目的时候经常会碰到下面这样的情形

String a="hello"; 

String b="hello"; 

String c=new String("hello");

System.out.println(a==b);//true

System.out.println(a==c);//false

System.out.println(a.equal(c))//true

为什么会出现这样的结果呢?

分析:这三个引用指向的的对象的内容都是相同的,从逻辑上面来说都是相等的。但是确实出现了上面的这种结果。那是因为==比的是对象的地址,对于同一个常量来说,它的内存地址都是一样的,而c是指向新开除来内存,所以a==c是false,而a.equal(b)比的是对象的内容,与对象所在的地址无关,所以a.equal(c)是true。

4、null类型之间的比较,

可以按照eclipse里面自动生成的equal函数的比较方式。任何其他类型跟null比较都是不等的,null。equal(null)是无意义的。

总结:

1、基本类型之间的比较一般是用==,但是注意float和double类型的精度问题以及NaN、正无穷大、负无穷大、-0.0、0.0的比较问题

2、引用类型的比较一般是用equal,尤其是字符串,因为==是指对象地址之间的比较,而对象地址之间的比较一般是无意义的。

0 0
原创粉丝点击