Java中各种类型数值的大小比较

概述

java中的数据类型,可分为两种:

  1. 基本数据类型,也称原始数据类型。byte,shrot,char,int,long,float,double,boolean(存储在内存中的堆栈(以后简称栈))

    • 他们之间的比较,应用双等号(==),比较 的是他们的值
  2. 引用类型(类,复合数据类型)(在栈中仅仅是存储引用类型的变量的地址,而其本身则存储在堆中)

    • 当他们用(==)进行比较的,比较的是他们在内存中的存放地址,(即栈中的内容是否相等)所以,除非是同一个new出来的对象,他们的比较后的 结果为true,否则比较后的结果为false。重写后的equals操作表示的两个变量是否是对同一个对象的引用(即堆中的内容是否相等)

java当中所有的类都是继承于Object这个超类的,在Object超类中的定义了一个equals的方法,这个方法的初始行为是用于检测一个对象是否等于另外一个对象,它将判断两个对象是否具有相同的引用(对象的内存地址即存放在栈中的地址,也是用==进行比较),如果两个对象的具有相同的引用,他们一定是相等的。然而,经常需要检测两个对象的内容是否相等,所以在一些类库中这个方法被重写(覆盖)掉了,String,Integer,Date在这些类中的equals有其自身的实现,而不再是比较类在栈内存中的存放地址了,而是比较该地址所指向的真实内容是否相等。

简单数据类型和封装类中的equals和”==”

Java为每一个简单数据类型提供了一个封装类,每个基本数据类型可以封装成对象类型。
除int(Integer)和char(Character),其余类型首字母大写即成封装类类型名。double (Double),float(Float),long(Long), short(Short),byte(Byte),boolean(Boolean)。

以int和Integer为例说明

Java中int和Integer区别如下:

  1. int是基本的数据类型,默认值可以为0
  2. Integer是int的封装类,默认值为null
  3. int和Integer都可以表示某一个数值

“equals”比较

Integer的equals(Object obj)方法,在equals(Object obj)方法中,会先判断参数中的对象obj是否是Integer同类型的对象,如果是则判断值(即地址指向的真实内容)是否相同,值相同则返回true,值不同则返回false,如果obj不是Integer类的对象,则返回false。
需要注意的是:当参数是基本类型int时,编译器会给int自动装箱成Integer类,然后再进行比较。

  1. 基本类型(值类型)之间无法使用equals比较。
  2. equals参数为值类型,则参数会进行自动装箱为包装类型,之后请参见第3点。
  3. equals参数为包装类型,则先比较是否为同类型,非同类型直接返回false,同类型再比较值。

例如:

  1. new Long(0).equals(0) 为 false,equals参数默认为int类型,装箱为Integer类型,不同类型直接返回false
  2. new Integer(500).equals(500) 为 true,equals参数默认为int类型,装箱为Integer类型,相同类型再比较值返回true
  3. new Integer(500).equals((short)500) 为 false,equals参数为short类型,装箱为Short类型,不同类型直接返回false
  4. new Long(0).equals(0L)为 true,equals参数为long类型,装箱为Long类型,相同类型再比较值返回true

“==”比较

  1. 基本类型之间互相比较:以值进行比较
  2. 一边是基本类型,一边是包装类型
    1. 同类型的进行比较,如Integer 与int,Long与long进行==比较时,会自动拆箱比较值
    2. 不同类型之间进行比较,则会自动拆箱,且会进行自动向上转型再比较值(低级向高级是隐式类型转换如:byte<short<int<long<float<double,高级向低级必须强制类型转换
  3. 两边都是包装类型则直接比较引用地址,但是要注意IntegerCache除外。

IntegerCache 缓存

JAVA的Integer有IntegerCache会缓存-128~127之间的对象。

如:Integer x = 100,会调用Integer的valueOf()方法,这个方法就是返回一个Integer对象,但是在返回前,作了一个判断,判断要赋给对象的值是否在[-128,127]区间中,且IntegerCache(是Integer类的内部类,里面有一个Integer对象数组,用于存放已经存在的且范围在[-128,127]中的对象)中是否存在此对象,如果存在,则直接返回引用,否则,创建一个新对象返回。

1
2
3
4
5
6
7
Integer i02 = 59;
Integer i03 = Integer.valueOf(59);
Integer i04 = new Integer(59);

System.out.println(i02 == i03); //true 因为59位于缓存区间直接从缓存中获取
System.out.println(i02 == i04); //false
System.out.println(i03 == i04); //false

再看一些例子

1
2
3
4
5
6
7
Integer i02 = 200;
Integer i03 = Integer.valueOf(200);
Integer i04 = new Integer(200);

System.out.println(i02 == i03); //false 因为200超出缓存区间从新创建对象
System.out.println(i02 == i04); //false
System.out.println(i03 == i04); //false

int与Integer

1
2
3
4
int a=55,b=201;
Integer at=55,bt=201;
System.out.println(a==at); //true 自动拆箱,和 IntegerCache 没关系
System.out.println(b==bt); //同上

总结

  1. 从数据类型看:int和long是基本数据类型,对其赋值属于数值引用,只能对其进行数值运算
    Integer和Long是对象类型,既然是对象那就有属性,有方法,这都是基本数据类型不包含的。

  2. 在实际使用中,对二者要注意的便是,int和long的默认值是0,使用时不用对其做null判断,也就不会出现NoPointerException这种异常,反之,Integer和Long的默认值是null,当对其使用toString()等方法时,如果不判断null就很有可能出现空指针异常。
    再者在定义表结构时,如果设主键为自增长型的,那只能是int或long。至于其它字段要看情况了,如果不能为null,且是数字型的那就设定为基本数据类型的,

  3. 拆箱与装箱
    Java的基本数据类型有:boolean char byte short int float long double
    对应的对象(即包装类)为:Boolean Character Byte Short Integer Float Long Double
    所谓的拆箱就是对象类型转基本数据类型时,会隐式的调用valueOf()方法去比较值的大小。
    装箱就是在进行类似Integer a=100时类似的操作时,就如同执行了Integer a=new Integer(100)的构造方法去创建a这个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//属于自动装箱,把值直接赋给一个对象.在自动打包时,127~-128的数值在内存会供重用
Integer a=100;
Integer b=100;

//true 虽然比较的是两个对象,但是jdk5后,对-128-127这个范围内的整形对象进行了缓存,实际是自动调用了两个Integer的valueOf()方法
System.out.println(a==b);
Integer c=1000;
Integer d=1000;

//false 比较的是两个对象,虽然值一样,但是引用地址不一样,且不再-128-127之间所以不会默认调用valueOf方法
System.out.println(c==d);
System.out.println(c.equals(d));//true 比较的是两个对象的值

int e=1000;
System.out.println(e==c);//true c自动拆包,对象c隐式的调用了valueOf()方法,即自动拆包,比较二者的值
Integer f=new Integer(e);//非自动打包
System.out.println(f==e);//true 同上

Integer g=new Integer(c);
//false 虽然c对象作为入参放大到了g对象的构造函数里面,但是默认的构造函数参数是int类型,所以c自动拆包了,因此g和c是对象之间的比较
System.out.println(g==c);
System.out.println(g.equals(c));//true 比较值

Long al=127l;
Long bl=127l;
System.out.println(al==bl);//true -128-127之间,同int

Long cl=128l;
Long dl=128l;
System.out.println(cl==dl);//false 不在-128-127之间,同int

以下几种声明方式,字面量表示都是没有问题的。
无论用大写还是小写的l表是long类型都是一样的。

1
2
3
4
5
6
long a= 0;
long b= 0l;
long c= 0L;
double d = 0;
double e = 0d;
double f = 0D;

在开发中为了声明long类型最好还是用大写L,可读性好