Integer装箱拆箱机制

如果面试官问Integer与int的区别:估计大多数人只会说道两点,Ingeter是int的包装类,int的初值为0,Ingeter的初值为null。但是如果面试官再问一下Integer i = 1;int ii = 1; i==ii为true还是为false?估计就有一部分人答不出来了,如果再问一下其他的,估计更多的人会头脑一片混乱。所以我对它们进行了总结,希望对大家有帮助。

  首先看代码:

 package com.test;
 2 /**
 3  * 
 4  * @author 刘玲
 5  *
 6  */
 7 public class TestInteger {
 8 
 9     /**
10      * @param args
11      */
12     public static void main(String[] args) {
13         int i = 128;
14         Integer i2 = 128;
15         Integer i3 = new Integer(128);
16         //Integer会自动拆箱为int,所以为true
17         System.out.println(i == i2);
18         System.out.println(i == i3);
19         System.out.println("**************");
20         Integer i5 = 127;//java在编译的时候,被翻译成-> Integer i5 = Integer.valueOf(127);
21         Integer i6 = 127;
22         System.out.println(i5 == i6);//true
23         /*Integer i5 = 128;
24         Integer i6 = 128;
25         System.out.println(i5 == i6);//false
26 */        Integer ii5 = new Integer(127);
27         System.out.println(i5 == ii5); //false
28         Integer i7 = new Integer(128);
29         Integer i8 = new Integer(123);
30         System.out.println(i7 == i8);  //false
31     }
32 
33 }

复制代码

首先,17行和18行输出结果都为true,因为Integer和int比都会自动拆箱(jdk1.5以上)。

22行的结果为true,而25行则为false,很多人都不动为什么。其实java在编译Integer i5 = 127的时候,被翻译成-> Integer i5 = Integer.valueOf(127);所以关键就是看valueOf()函数了。只要看看valueOf()函数的源码就会明白了。JDK源码的valueOf函数式这样的:

1 public static Integer valueOf(int i) {
2         assert IntegerCache.high >= 127;
3         if (i >= IntegerCache.low && i <= IntegerCache.high)
4             return IntegerCache.cache[i + (-IntegerCache.low)];
5         return new Integer(i);
6     }

看一下源码大家都会明白,对于-128到127之间的数,会进行缓存,Integer i5 = 127时,会将127进行缓存,下次再写Integer i6 = 127时,就会直接从缓存中取,就不会new了。所以22行的结果为true,而25行为false。

对于27行和30行,因为对象不一样,所以为false。

我对于以上的情况总结如下:

  ①无论如何,Integer与new Integer不会相等。不会经历拆箱过程,i3的引用指向堆,而i4指向专门存放他的内存(常量池),他们的内存地址不一样,所以为false
  ②两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false
  java在编译Integer i2 = 128的时候,被翻译成-> Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存
  ③两个都是new出来的,都为false
  ④int和integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比

 

====================================================

经过强制类型转换以后,变量a,b的值分别为多少?

1

2

shorta =128

byteb =(byte) a;

 

正确答案: B   你的答案: C (错误)

128  127
128 - 128
128  128
编译错误

 

 

=================================

  

面试题:

复制代码

//在jdk1.5的环境下,有如下4条语句:

Integer i01 = 59;
int i02 = 59;
Integer i03 =Integer.valueOf(59);
Integer i04 = new Integer(59);

以下输出结果为false的是:

A.   System.out.println(i01== i02);   //true
B.   System.out.println(i01== i03);   //true
C.   System.out.println(i03== i04);   //false
D.   System.out.println(i02== i04);   //true

复制代码

1.题目中提到了,是Jdk1.5的环境。

OK,我们新建一个项目,新建一个类,把代码复制进去。将Java Compiler设置为1.5.  关于这个版本的问题稍后再谈。

2.这里有两个数据类型,int和Integer。

   int为基本类型。

   Integer为对象类型。Integer的类声明是这样的:

复制代码

public final class Integer extends Number implements Comparable<Integer> {

    //...

}

1、Integer类是final的,不能被继承

 

2、Integer类实现了Comparable接口,所以可以用compareTo进行比较。

 

3、Integer继承了Number类,所以该类可以调用longValue、floatValue、doubleValue等系列方法返回对应的类型的值。

 

复制代码

3.题目中声明了三个Integer变量,i01,i03,i04.这三种声明方式有啥区别呢?

 

3.1  Integer i04 = new Integer(59); 做了什么?

看源码,这个构造函数是这样的:

复制代码

    /**
     * The value of the {@code Integer}.
     *
     * @serial
     */
    private final int value;

    /**
     * Constructs a newly allocated {@code Integer} object that
     * represents the specified {@code int} value.
     *
     * @param   value   the value to be represented by the
     *                  {@code Integer} object.
     */
    public Integer(int value) {
       this.value = value;
    }

复制代码

new Integer(59)的这个操作,调用了构造函数,将59这个值,赋给了Integer的局部变量value。

 

3.2  Integer i03 = Integer.valueOf(59); //这个 Integer.valueOf 方法又做了什么??

看Integer.valueOf源码:

复制代码

    /**
     * Returns an {@code Integer} instance representing the specified
     * {@code int} value.  If a new {@code Integer} instance is not
     * required, this method should generally be used in preference to
     * the constructor {@link #Integer(int)}, as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     *
     * @param  i an {@code int} value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        assert IntegerCache.high >= 127;
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

复制代码

这里,valueOf方法先判断传入参数的值,满足if 条件的话,则返回cache值。

否则 new 一个Integer 返回。这里的 if中的条件 IntegerCache.high=127, IntegerCache.low=-128;从IntegerCache的类定义可以看出,IntegerCache里边定义了一个数组cache用来存储Integer对象,静态块里边完成了数组的初始化,存入了-128到127之间的Integer对象:

复制代码

    private static class IntegerCache {//这个类是 Integer 类的 静态内部类。看这个代码不难发现,在Integer加载之后这个内部类的cache数组里边就初始化了-128到127之间的值
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low));
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }

        private IntegerCache() {}
    }

复制代码

所以,对于Integer.valueOf(i)方法 , 当i在-128-127之间时返回的是缓存的Integer对象。 否则返回的是一个新的Integer对象。

这里传递的是59,所以返回的是cache里边的对象。

3.3 Integer i01 = 59;// 这句话又做了什么?

我们将源码产生的class文件反编译发现如下:

复制代码

源码:   
public static void main(String[] args) {
        // TODO Auto-generated method stub

        Integer i01 = 59;// Integer.valueOf(59);
        int i02 = 59;
        Integer i03 = Integer.valueOf(59);
        Integer i04 = new Integer(59);
        System.out.println("i01 == i02:" + (i01 == i02)); 
        System.out.println("i01 == i03:" + (i01 == i03));
        System.out.println("i03 == i04:" + (i03 == i04));
        System.out.println("i02 == i04:" + (i02 == i04)); 
        
    }
反编译之后:

public static void main(String[] args)
{
Integer i01 = Integer.valueOf(59);
int i02 = 59;
Integer i03 = Integer.valueOf(59);
Integer i04 = new Integer(59);
System.out.println("i01 == i02:" + (i01.intValue() == i02));
System.out.println("i01 == i03:" + (i01 == i03));
System.out.println("i03 == i04:" + (i03 == i04));
System.out.println("i02 == i04:" + (i02 == i04.intValue()));
}

 

复制代码

 

可以发现:Integer i01=59;在反编译过来之后是Integer.valueOf(59);

在用Integer 类型的i01和int类型的i02进行“==”比较的时候,反编译过来的是:i01.intValue() == i02

这两个操作分别为 自动装箱 和自动拆箱。这个特性是在java1.5开始才有的。所以第一点中提到了jdk版本为1.5.

 

如果我们在eclipse/myeclipse 中将java compiler设置成1.5以下的就会无法通过编译:

Type mismatch: cannot convert from int to Integer

 

 

通过上面的分析,这题就不难得出答案了。

i01 == i02 等价于  i01.intValue()==i02  两个值的比较59==59   -->true;

i01 == i03 由于 59在-128到127之间,所以,i01和i03的赋值操作返回的是同一个对象。都是从chche中返回的同一个对象,对象地址相同   true;

i03 == i04 i03是来自缓存值,i04是新new的对象 ,二者不是同一个对象,所以false。

i02 == i04 和第一个类似,true。

 

============================

 

转载:http://blog.csdn.net/tingzhiyi/article/details/52344845

来源于牛客网的一道选择题:

Java语言的下面几种数组复制方法中,哪个效率最高?

 

A.for循环逐一复制
B.System.arraycopy
C.System.copyof
D.使用clone方法

 

效率:System.arraycopy > clone > Arrays.copyOf > for循环

 

1、System.arraycopy的用法:

 

[java] view plain copy

  1. public static void arraycopy(Object src,  
  2.                              int srcPos,  
  3.                              Object dest,  
  4.                              int destPos,  
  5.                              int length)  

 

参数: src - 源数组。 srcPos - 源数组中的起始位置。 dest - 目标数组。 destPos - 目标数据中的起始位置。 length - 要复制的数组元素的数量

 

应用实例:

 

[java] view plain copy

  1. public class Main{  
  2.     public static void main(String[] args) {  
  3.   
  4.          int[] a1={1,2,3,4,5,6};  
  5.          int[] a2={11,12,13,14,15,16};  
  6.            
  7.          System.arraycopy(a1, 2, a2, 3, 2);  
  8.          System.out.print("copy后结果:");  
  9.          for(int i=0;i<a2.length;i++){  
  10.              System.out.print(a2[i]+" ");      
  11.          }  
  12.     }  
  13. }  

运行结果:

 


 

2、clone 的用法:

java.lang.Object类的clone()方法为protected类型,不可直接调用,需要先对要克隆的类进行下列操作:

首先被克隆的类实现Cloneable接口;然后在该类中覆盖clone()方法,并且在该clone()方法中调用super.clone();这样,super.clone()便可以调用java.lang.Object类的clone()方法。

应用实例:

 

[java] view plain copy

  1. //被克隆的类要实现Cloneable接口  
  2. class Cat implements Cloneable   
  3. {  
  4.     private String name;  
  5.     private int age;  
  6.     public Cat(String name,int age)  
  7.     {  
  8.         this.name=name;  
  9.         this.age=age;  
  10.     }  
  11.     //重写clone()方法  
  12.     protected Object clone()throws CloneNotSupportedException{    
  13.         return super.clone() ;    
  14.     }  
  15. }  
  16. public class Clone {  
  17.     public static void main(String[] args) throws CloneNotSupportedException {  
  18.   
  19.         Cat cat1=new Cat("xiaohua",3);  
  20.         System.out.println(cat1);  
  21.         //调用clone方法  
  22.         Cat cat2=(Cat)cat1.clone();  
  23.         System.out.println(cat2);  
  24.     }  
  25. }  

3、复制引用和复制对象的区别

 

复制引用:是指将某个对象的地址复制,所以复制后的对象副本的地址和源对象相同,这样,当改变副本的某个值后,源对象值也被改变;

复制对象:是将源对象整个复制,对象副本和源对象的地址并不相同,当改变副本的某个值后,源对象值不会改变;

 

[java] view plain copy

  1. Cat cat1=new Cat("xiaohua",3);//源对象  
  2.         System.out.println("源对象地址"+cat1);  
  3.         //调用clone方法,复制对象  
  4.         Cat cat2=(Cat)cat1.clone();  
  5.         Cat cat3=(Cat)cat1;//复制引用  
  6.         System.out.println("复制对象地址:"+cat2);  
  7.         System.out.println("复制引用地址:"+cat3);  

输出结果:

 


可以看出,复制引用的对象和源对象地址相同,复制对象和源对象地址不同

4、Arrays.copyOf 的用法:

Arrays.copyOf有十种重载方法,复制指定的数组,返回原数组的副本。具体可以查看jdk api

int转byte与补码的关系

int类型强制转换为 byte类型

  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         int start = -131;  
  4.         int end = 131;  
  5.   
  6.         for (int i = start; i < end; i++)   
  7.             if ((byte) i != i)   
  8.                 System.out.println("原数:" + i + "\t转化后:" + (byte) i);  
  9.     }  
  10.   
  11. }  

    程序运行结果如下:

Java代码  收藏代码

  1. 原数:-131 转化后:125  
  2. 原数:-130 转化后:126  
  3. 原数:-129 转化后:127  
  4. 原数:128  转化后:-128  
  5. 原数:129  转化后:-127  
  6. 原数:130  转化后:-126  

    为什么会出现这种情况呢?

    因为Java中byte是用8位来存储,只能表示-128~127之间的数,当由int强制类型转化为byte时,系统就采取了截取int后8位的做法。

Java代码  收藏代码

  1. //java采用补码存储整数,int型为32位,byte为8位  
  2. //那么130在内存中的表示形式:00000000 00000000 00000000 10000010  
  3. //这样截取后8位就变成10000010,补码表示的时候第一位是符号位,0正1负,  
  4. //所以可以知道10000010肯定是一个负数了,再来看它的数值部分,  
  5. //补码由正数变负数,还是正数变负,方法:“按位取反,再加1”,  
  6. //所以0000010应该变为1111101 + 1 = 1111110(即126)  
  7. //又因为是负数,所以就截取变成-126了  
  8.   
  9. //我们再来看下-130的例子(符号位是1,其余按位取反+1)  
  10. //-130在内存中的表示形式:11111111 11111111 11111111 01111110  
  11. //这样截取后8位就变成01111110  
  12. //显然这是整数啊,然后数值部分是126  
  13. //64+32+16+8+4+2=126  
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值