类型

区别 int Integer 注意
Class int java.lang.Integer int.class != Integer.class, 反射时需区分
内存位置 Integer 跟其他普通对象一样存在堆里
初始值 0 null int 没法指定为 null
int a = 123;
int b = 123;
Integer c = 123;
Integer d = 123;
Integer e = new Integer(123);
Integer f = new Integer(123);
Integer g = Integer.valueOf(123);
Integer h = Integer.valueOf(123);

System.identityHashCode 查看具体位置:

System.out.println(System.identityHashCode(a));//41903949
System.out.println(System.identityHashCode(b));//41903949
System.out.println(System.identityHashCode(c));//41903949
System.out.println(System.identityHashCode(d));//41903949
System.out.println(System.identityHashCode(e));//488970385
System.out.println(System.identityHashCode(f));//1209271652
System.out.println(System.identityHashCode(g));//41903949
System.out.println(System.identityHashCode(h));//41903949
  • 123 是是一个 [-128, +127] 范围内的数, 后续会提到;
  • 以上使用 equals 比较, 相互都相等;
  • 以上 Integer 对象之间使用 == 比较, 根据存储位置, 一致的才相等;
  • 以上 int 和 Integer 之间 == 比较, 受自动拆箱影响, 相等;

包装类对应表:

原始类型 包装类型
boolean Boolean
byte Byte
char Character
float Float
double Double
int Integer
long Long
short Short

自动装箱 自动拆箱

先说 int 和 Integer 的装箱/拆箱:

//把 int 赋值给 Integer 即为自动装箱, 等效于 `Integer a = Integer.valueOf(123);`.
Integer a = 123;

//把 Integer 赋值给 int 即为自动拆箱, 等效于 `int b = a.intValue();`
int b = a;

要点:

  • 对于 [-128, 127] 范围内的数, Integer#valueOf 会使用缓存, 其他范围直接 new Integer (127 的上限可以配置).
  • int 赋值给 Object 会触发自动装箱;
  • 遇到 == + * 等算数表达式的时候, 会触发自动拆箱, 都转为基本类型再比较.
  • 如果 == 比较两个对象, 则比较他们是否指向同一个对象;
  • equals 左操作数只能是对象, 右操作数会先装箱再拆箱, 最终用 == 比较基本数据类型;
  • equals 比较 Integer 和 Long 直接返回 false;
  • (++a).getClass() => class java.lang.Integer

具体实现

Integer

    @HotSpotIntrinsicCandidate
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }    

Long

    @HotSpotIntrinsicCandidate
    public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
    }
    public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }

Double

    @HotSpotIntrinsicCandidate
    public static Double valueOf(double d) {
        return new Double(d);
    }

    public boolean equals(Object obj) {
        return (obj instanceof Double)
               && (doubleToLongBits(((Double)obj).value) ==
                      doubleToLongBits(value));
    }

测验

        int a = 123;
        int aa = 123;

        Integer b = 123;
        Integer bb = 123;

        Integer c = 1230;
        Integer cc = 1230;

        Long d = 1230L;
        Long dd = 1230L;

        Double e = 3.14D;
        Double ee = 3.14D;

        System.out.println(a == aa);//true
        System.out.println(b == bb);//true
        System.out.println(c == cc);//false
        System.out.println(d == dd);//false
        System.out.println(e == ee);//false

        System.out.println(a == b);//true
        System.out.println((b * 10) == c);//true
        System.out.println((b * Integer.valueOf(10)) == c);//true

//        System.out.println((c == d);//syntax error
        System.out.println((c * 1) == d);//true
        System.out.println(c.equals(cc));//true
        System.out.println(c.equals(1230));//true
        System.out.println(c.equals(1230L));//false
        System.out.println(c.equals(d));//false
        System.out.println(d.equals(1230));//false
        System.out.println(d.equals(1230L));//true
        System.out.println(e.equals(ee));//true
        System.out.println(e.equals(3.14D));//true

设计模式

对于 Integer 类来说, 他使用了 享元模式, 其中 内部的 value 是他的 .

享元模式跟单例结构上看起来有点类似, 区别是享元返回的对象不一定都指向同一个. 就如上面例子所示, 超出 [-128, +127] 范围的数会得到不同的两个对象.