精华内容
下载资源
问答
  • 面试官:兄弟,说说基本类型和包装类型的区别吧

    万次阅读 多人点赞 2019-09-29 08:36:07
    Java 的每个基本类型都对应了一个包装类型,比如说 int 的包装类型为 Integer,double 的包装类型为 Double。基本类型和包装类型的区别主要有以下 4 点。

    六年前,我从苏州回到洛阳,抱着一幅“海归”的心态,投了不少简历,也“约谈”了不少面试官,但仅有两三个令我感到满意。其中有一位叫老马,至今还活在我的手机通讯录里。他当时扔了一个面试题把我砸懵了:说说基本类型和包装类型的区别吧。

    我当时二十三岁,正值青春年华,从事 Java 编程已有 N 年经验(N < 4),自认为所有的面试题都能对答如流,结果没想到啊,被“刁难”了——原来洛阳这块互联网的荒漠也有技术专家啊。现在回想起来,脸上不自觉地泛起了羞愧的红晕:主要是自己当时太菜了。不管怎么说,是时候写篇文章剖析一下基本类型和包装类型的区别了。

    Java 的每个基本类型都对应了一个包装类型,比如说 int 的包装类型为 Integer,double 的包装类型为 Double。基本类型和包装类型的区别主要有以下 4 点。

    01、包装类型可以为 null,而基本类型不可以

    别小看这一点区别,它使得包装类型可以应用于 POJO 中,而基本类型则不行。

    POJO 是什么呢?这里稍微说明一下。

    POJO 的英文全称是 Plain Ordinary Java Object,翻译一下就是,简单无规则的 Java 对象,只有属性字段以及 setter 和 getter 方法,示例如下。

    class Writer {
    	private Integer age;
    	private String name;
    
    	public Integer getAge() {
    		return age;
    	}
    
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    }
    

    和 POJO 类似的,还有数据传输对象 DTO(Data Transfer Object,泛指用于展示层与服务层之间的数据传输对象)、视图对象 VO(View Object,把某个页面的数据封装起来)、持久化对象 PO(Persistant Object,可以看成是与数据库中的表映射的 Java 对象)。

    那为什么 POJO 的属性必须要用包装类型呢?

    《阿里巴巴 Java 开发手册》上有详细的说明,我们来大声朗读一下(预备,起)。

    数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出 NullPointerException 的异常。

    02、包装类型可用于泛型,而基本类型不可以

    泛型不能使用基本类型,因为使用基本类型时会编译出错。

    List<int> list = new ArrayList<>(); // 提示 Syntax error, insert "Dimensions" to complete ReferenceType
    List<Integer> list = new ArrayList<>();
    

    为什么呢?因为泛型在编译时会进行类型擦除,最后只保留原始类型,而原始类型只能是 Object 类及其子类——基本类型是个特例。

    03、基本类型比包装类型更高效

    基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用。

    很显然,相比较于基本类型而言,包装类型需要占用更多的内存空间。假如没有基本类型的话,对于数值这类经常使用到的数据来说,每次都要通过 new 一个包装类型就显得非常笨重。

    03、两个包装类型的值可以相同,但却不相等

    两个包装类型的值可以相同,但却不相等——这句话怎么理解呢?来看一段代码就明明白白了。

    Integer chenmo = new Integer(10);
    Integer wanger = new Integer(10);
    
    System.out.println(chenmo == wanger); // false
    System.out.println(chenmo.equals(wanger )); // true
    

    两个包装类型在使用“”进行判断的时候,判断的是其指向的地址是否相等。chenmo 和 wanger 两个变量使用了 new 关键字,导致它们在“”的时候输出了 false。

    chenmo.equals(wanger) 的输出结果为 true,是因为 equals 方法内部比较的是两个 int 值是否相等。源码如下。

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

    瞧,虽然 chenmo 和 wanger 的值都是 10,但他们并不相等。换句话说就是:将“==”操作符应用于包装类型比较的时候,其结果很可能会和预期的不符

    04、自动装箱和自动拆箱

    既然有了基本类型和包装类型,肯定有些时候要在它们之间进行转换。把基本类型转换成包装类型的过程叫做装箱(boxing)。反之,把包装类型转换成基本类型的过程叫做拆箱(unboxing)。

    在 Java SE5 之前,开发人员要手动进行装拆箱,比如说:

    Integer chenmo = new Integer(10);  // 手动装箱
    int wanger = chenmo.intValue();  // 手动拆箱
    

    Java SE5 为了减少开发人员的工作,提供了自动装箱与自动拆箱的功能。

    Integer chenmo  = 10;  // 自动装箱
    int wanger = chenmo;     // 自动拆箱
    

    上面这段代码使用 JAD 反编译后的结果如下所示:

    Integer chenmo = Integer.valueOf(10);
    int wanger = chenmo.intValue();
    

    也就是说,自动装箱是通过 Integer.valueOf() 完成的;自动拆箱是通过 Integer.intValue() 完成的。理解了原理之后,我们再来看一道老马当年给我出的面试题。

    // 1)基本类型和包装类型
    int a = 100;
    Integer b = 100;
    System.out.println(a == b);
    
    // 2)两个包装类型
    Integer c = 100;
    Integer d = 100;
    System.out.println(c == d);
    
    // 3)
    c = 200;
    d = 200;
    System.out.println(c == d);
    

    答案是什么呢?有举手要回答的吗?答对的奖励一朵小红花哦。

    第一段代码,基本类型和包装类型进行 == 比较,这时候 b 会自动拆箱,直接和 a 比较值,所以结果为 true。

    第二段代码,两个包装类型都被赋值为了 100,这时候会进行自动装箱,那 == 的结果会是什么呢?

    我们之前的结论是:将“==”操作符应用于包装类型比较的时候,其结果很可能会和预期的不符。那结果是 false?但这次的结果却是 true,是不是感觉很意外?

    第三段代码,两个包装类型重新被赋值为了 200,这时候仍然会进行自动装箱,那 == 的结果会是什么呢?

    吃了第二段代码的亏后,是不是有点怀疑人生了,这次结果是 true 还是 false 呢?扔个硬币吧,哈哈。我先告诉你结果吧,false。

    为什么?为什么?为什么呢?

    事情到了这一步,必须使出杀手锏了——分析源码吧。

    之前我们已经知道了,自动装箱是通过 Integer.valueOf() 完成的,那我们就来看看这个方法的源码吧。

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

    难不成是 IntegerCache 在作怪?你猜对了!

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
    
        static {
            // high value may be configured by property
            int h = 127;
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            high = h;
    
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
    
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }
    }
    

    大致瞟一下这段代码你就全明白了。-128 到 127 之间的数会从 IntegerCache 中取,然后比较,所以第二段代码(100 在这个范围之内)的结果是 true,而第三段代码(200 不在这个范围之内,所以 new 出来了两个 Integer 对象)的结果是 false。

    看完上面的分析之后,我希望大家记住一点:当需要进行自动装箱时,如果数字在 -128 至 127 之间时,会直接使用缓存中的对象,而不是重新创建一个对象

    自动装拆箱是一个很好的功能,大大节省了我们开发人员的精力,但也会引发一些麻烦,比如下面这段代码,性能就很差。

    long t1 = System.currentTimeMillis();
    Long sum = 0L;
    for (int i = 0; i < Integer.MAX_VALUE;i++) {
        sum += i;
    }
    long t2 = System.currentTimeMillis();        
    System.out.println(t2-t1);
    

    sum 由于被声明成了包装类型 Long 而不是基本类型 long,所以 sum += i 进行了大量的拆装箱操作(sum 先拆箱和 i 相加,然后再装箱赋值给 sum),导致这段代码运行完花费的时间足足有 2986 毫秒;如果把 sum 换成基本类型 long,时间就仅有 554 毫秒,完全不一个等量级啊。

    05、最后

    谢谢大家的阅读,原创不易,喜欢就点个赞,这将是我最强的写作动力。如果你觉得文章对你有所帮助,也蛮有趣的,就关注一下我的公众号,谢谢。

    展开全文
  • 一、基本类型 Java一种静态编程语言,所有变量和表达式是在编译时就确定的。同时,Java又是一种强类型语言,所有的变量和表达式都有具体的类型,并且每种类型是严格定义的。类型限制了变量可以hold什么样的值,...

    一、基本类型

    Java一种静态编程语言,所有变量和表达式是在编译时就确定的。同时,Java又是一种强类型语言,所有的变量和表达式都有具体的类型,并且每种类型是严格定义的。类型限制了变量可以hold什么样的值,表达式最终会产生什么样的值,可以进行哪些操作。在Java中共有8中基本类型数据,同时每种基本类型又有对应的包装类。

    最简单的理解,基本类型有默认值,而包装类型初始为null。然后再根据这两个特性进行分业务使用,在阿里巴巴的规范里所有的POJO类必须使用包装类型,而在本地变量推荐使用基本类型。 

    基本类型介绍

    Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。 

    1、整数:包括int、short、byte、long初始值为0。

    2、浮点型:float、double初始值为0.0

    3、字符:char初始值为空格,即'' ",如果输出,在Console上是看不到效果的。

    4、布尔:boolean初始值为false 

    基本型别大小最小值最大值包装类
    boolean----------------Boolean
    char16-bitUnicode 0Unicode 2^16-1Character
    byte8-bit-128+127Byte
    short16-bit-2^15+2^15-1Short
    int32-bit-2^31+2^31-1Integer
    long64-bit-2^63+2^63-1Long
    float32-bitIEEE754IEEE754Float
    double64-bitIEEE754IEEE754Double

     基本类型的运算和相互转换

    基本类型运算

    boolean类型数据可以进行逻辑运算(&&、||、!),其他的基本类型都可以进行数值计算(+、-、*、/、%等)。逻辑运算比较简单易懂,完全与逻辑数学的规则一致。而数值运算涉及到运算后的结果的类型问题,稍微比较复杂一点。一般来说,运算最终结果的类型与表达式中的最大(占用空间最大)的类型。

    long l = 1 + 2L;      // 与1L的类型一致
    int i = 1 + 2L;       //编译不通过
    float f = 1 + 2 + 1.2f;      //与1.2f的类型一致
    double d = 1 + 2 + 1.2;        //与1.2的类型一致

    如果两种相同的类型的数据进行运算,按理来说,运算结果应该还是那个类型。但事实上,bytecharshort等类型是满足这个结论的。

    // 编译不通过,编辑器报:Type mismatch: cannot convert from int to byte 。
    byte s1 = 1;
    byte s2 = 1;
    byte s = s1 + s2;
    
    // 编译不通过,编辑器报:Type mismatch: cannot convert from int to char 。
    char s1 = 1;
    char s2 = 1;
    char s = s1 + s2;
    
    // 编译不通过,编辑器报:Type mismatch: cannot convert from int to short 。
    short s1 = 1;
    short s2 = 1;
    short s = s1 + s2;

    从字面上来看,1+1=2绝对没有超过这个类型的范围。下面的例子都可以编译通过

    byte s1 = 1 + 1;
    char s2 = 1 + 1;
    short s3 = 1 + 1;

    这是因为Java中的数值运算最低要求是int类型,如果参与运算的变量类型都没有超过int类型,则它们都会被自动升级为int类型再进行运算,所以它们运算后的结果类型也是int类型。这种方式所得到结果是否超过了对应类型所表示的范围只能在运行时才能确定,在编译时是无法知晓的。而编译器会直接将byte s1 = 1 + 1编译成byte s1 = 2,这个表达式在编译器就可以确定是合法表达式,故可以通过编译。可以通过字节码来进行佐证。

    short s = 1 + 1;

    上面伪代码所对应的字节码如下,iconst_2表示直接生成常量,然后赋值给s变量。

    Code:
          stack=1, locals=2, args_size=1
             0: iconst_2
             1: istore_1
             2: return

    类型转换

    Java中除了boolean类型之外,其他7中类型相互之间可以进行转换。转换分为自动转换和强制转换。对于自动转换(隐式),无需任何操作,而强制类型转换需要显式转换,即使用转换操作符(type)。7种类型按照其占用空间大小进行排序:

    byte <(short=char)< int < long < float < double

    类型转换的总则是:小可直接转大、大转小会失去精度。这句话的意思是较小的类型直接转换成较大的类型,没有任何印象;而较大的类型也可以转换为较小的类型,但是会失去精度。他们之间的转换都不会抛出任何运行时异常。小转大是Java帮我们自动进行转换的,与正常的赋值操作完全一样;大转小需要进行强制转换操作,其语法是target-type var =(target-type) value。

    // 自动转换
    long l = 10;
    double d = 10;
    float = 10;
    
    // 强制转换
    int a = (int) 1.0;
    char c = (char) a;

    值得注意是,大转小是一个很不安全的动作,可能导致莫名其妙的错误。譬如在下面的代码中,1111111111111L强转成int类型后,其值(-1285418553)与转换前的值相差巨大。这是由于在进行强制转换时,在二进制层面上直接截断,导致结果“面目全非”。

    二、包装类型 

    Java中每一种基本类型都会对应一个唯一的包装类,基本类型与其包装类都可以通过包装类中的静态或者成员方法进行转换。每种基本类型及其包装类的对应关系如下,值得注意的是,所有的包装类都是final修饰的,也就是它们都是无法被继承和重写的。

    包装类与基本类型的转换

    基本类型------>包装器类
    Integer obj=new Integer(145);
    
    包装器类------>基本类型
    int num=obj.intValue();
    
    字符串------>包装器类
    Integer obj=new Integer("-45.36");
    
    包装器类------>字符串包装器类
    String str=obj.toString();
    
    字符串------>基本类型
    int num=Integer.parseInt("-45.36");
    
    基本类型------>字符串包装器类
    String str=String.valueOf(5);

     

     “莫名其妙”的NullPointException在笔者开发经历中,碰到过不少因为请求参数或者接口定义字段设置为int(或者其他基本类型)而导致NullPointException。代码大致地运行步骤如下所示,当然不会跟这个完全一样。

    Integer a =null;...intb = a;// 抛出NullPointException上面的代码可以编译通过,但是会抛出空指针异常(NullPointException)。前面已经说过了,int b = a实际上是int b = a.intValue(),由于a的引用值为null,在空对象上调用方法就会抛出NullPointException。

    三、拆箱与装箱 

    JDK1.5的新特性:自动装包/拆包(Autoboxing/unboxing)

      自动装包/拆包大大方便了基本类型数据和它们包装类地使用。

      自动装包:基本类型自动转为包装类.(int >> Integer)

      自动拆包:包装类自动转为基本类型.(Integer >> int)

      在JDK1.5之前,我们总是对集合不能存放基本类型而耿耿于怀,现在自动转换机制解决了我们的问题。

    Java作为一种强类型的语言,对象直接赋值给引用类型变量,而基础数据只能赋值给基本类型变量,这个是毫无异议的。那么基本类型和包装类型为什么可以直接相互赋值呢?这其实是Java中的一种“语法糖”。“语法糖”是指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会(来自百度百科)。换句话说,这其实是一种障眼法,那么实际上是怎么样的呢?下面是Integer a = 1;语句编译的字节码。

    0: iconst_1
    1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
    4: astore_1

    首先,生成一个常量1,然后调用Integer.valueOf(int)方法返回Integer对象,最后将对象的地址(引用)赋值给变量a。Integer a = 1;其实相当于Integer a = Integer.valueOf(1);。其他的也类似,比如Double、Character,不相信的朋友可以自己手动尝试一下。

    Integer

    在Java中,“==”符号判断的内存地址所对应的值得相等性,具体来说,基本类型判断值是否相等,引用类型判断其指向的地址是否相等。看看下面的代码,两种类似的代码逻辑,但是得到截然不用的结果。

    Integer a1 = 1;
    Integer a2 = 1;
    System.out.println(a1 == a2); // true
    
    Integer b1 = 222;
    Integer b2 = 222;
    System.out.println(b1 == b2); // false

     这个必须从源代码中才能找到答案。Integer类中的valueOf()方法的源代码如下:

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high) // 判断实参是否在可缓存范围内,默认为[-128, 127]
            return IntegerCache.cache[i + (-IntegerCache.low)]; // 如果在,则取出初始化的Integer对象
        return new Integer(i); // 如果不在,则创建一个新的Integer对象
    }

    由于1属于[-128, 127]集合范围内,所以valueOf()每次都会取出同一个Integer对象,故第一个“==”判断结果为true;而222不属于[-128, 127]集合范围内,所以valueOf()每次都会创建一个新的Integer对象,由于两个新创建的对象的地址不一样,故第一个“==”判断结果为false。 

    Double

    下面这段代码的输出结果又为什么不一样呢? 

            Double i1 = 100.0;
            Double i2 = 100.0;
            System.out.println(i1==i2);   //false
    
            Double i3 = 200.0;
            Double i4 = 200.0;       
            System.out.println(i3==i4);   //false

    至于具体为什么,读者可以去查看Double类的valueOf的实现。

      在这里只解释一下为什么Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现。很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是。

    Boolean

    下面这段代码输出结果又是什么?

            Boolean i1 = false;
            Boolean i2 = false;
            System.out.println(i1==i2);     //true
    
            Boolean i3 = true;
            Boolean i4 = true;         
            System.out.println(i3==i4);     //true

    至于为什么是这个结果,同样地,看了Boolean类的源码也会一目了然。下面是Boolean的valueOf方法的具体实现:

    public static Boolean valueOf(boolean b) {
            return (b ? TRUE : FALSE);
        }

    而其中的 TRUE 和FALSE又是什么呢?在Boolean中定义了2个静态成员属性:

    public static final Boolean TRUE = new Boolean(true);
    
    public static final Boolean FALSE = new Boolean(false);

    至此,大家应该明白了为何上面输出的结果都是true了

      注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。

         Double、Float的valueOf方法的实现是类似的。 

    谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别

    • 1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;
    • 2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。

    再来看看这个题,加深对装箱拆箱操作的理解

            Integer a = 1;
            Integer b = 2;
            Integer c = 3;
            Integer d = 3;
            Integer e = 321;
            Integer f = 321;
            Long g = 3L;
            Long h = 2L;
             
            System.out.println(c==d);            //true
            System.out.println(e==f);            //false
            System.out.println(c==(a+b));        //true
            System.out.println(c.equals(a+b));   //true
            System.out.println(g==(a+b));        //true
            System.out.println(g.equals(a+b));   //false
            System.out.println(g.equals(a+h));   //true

    注意:

    • 当 "=="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象
    • 如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)
    • 对于包装器类型,equals方法并不会进行类型转换

    第一个和第二个输出结果没有什么疑问。第三句由于  a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。同理对于后面的也是这样,不过要注意倒数第二个和最后一个输出的结果(如果数值是int类型的,装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法)。

    三、基本类型与包装类型的异同 

    1、在Java中,一切皆对象,但八大基本类型却不是对象。

    2、声明方式的不同,基本类型无需通过new关键字来创建,而封装类型需new关键字。

    3、存储方式及位置的不同,基本类型是直接存储变量的值保存在堆栈中能高效的存取,封装类型需要通过引用指向实例,具体的实例保存在堆中。

    4、初始值的不同,封装类型的初始值为null,基本类型的的初始值视具体的类型而定,比如int类型的初始值为0,boolean类型为false;

    5、使用方式的不同,比如与集合类合作使用时只能使用包装类型。

    6、什么时候该用包装类,什么时候用基本类型,看基本的业务来定:这个字段允不允许null值,如果允许null值,则必然要用封装类,否则值类型就可以了,用到比如泛型和反射调用函数.,就需要用包装类! 

    展开全文
  • java基本类型与引用类型

    万次阅读 多人点赞 2018-01-04 17:30:32
    java基本类型与引用类型 目录 java基本类型与引用类型 目录 一基本数据类型 二引用类型 三基本类型与引用类型的区别 默认值 内存分配 自动装箱自动拆箱 自动装箱拆箱带来的问题 程序的性能 空指针异常 ...

    java基本类型与引用类型


    目录

    一、基本数据类型

    java中一共分为8种基本数据类型:byte、short、int、long、float、double、char、boolean,其中byte、short、int、long是整型。float、double是浮点型,char是字符型,boolean是布尔型。

    二、引用类型

    java为每种基本类型都提供了对应的封装类型,分别为:Byte、Short、Integer、Long、Float、Double、Character、Boolean。引用类型是一种对象类型,它的值是指向内存空间的引用,就是地址。

    三、基本类型与引用类型的区别

    1.默认值

    整型byte、short、int、long的默认值都为0,浮点型float、double的默认值为0.0,boolean默认值为false,char默认值为空。对应的包装类型默认值都为null。

    2.内存分配

    基本数据类型的变量是存储在栈内存中,而引用类型变量存储在栈内存中,保存的是实际对象在堆内存中的地址,实际对象中保存这内容。

    3.自动装箱、自动拆箱

    Java从jdk1.5开始引入自动装箱和拆箱,使得基本数据类型与引用类型之间相互转换变得简单。

    自动装箱: java自动将原始类型转化为引用类型的过程,自动装箱时编译器会调用valueOf方法,将原始类型转化为对象类型。

    自动拆箱: java自动将引用类型转化为原始类型的过程,自动拆箱时编译器会调用intValue(),doubleValue()这类的方法将对象转换成原始类型值。

    自动装箱主要发生在两种情况:一种是赋值时,一种是方法调用时。
    a.赋值

    Integer a = 3; //自动装箱
    int b = a; //自动拆箱

    b.方法调用

    public Integer query(Integer a){
       return a;
    }
    query(3); //自动装箱
    int result = query(3); //自动拆箱

    4.自动装箱、拆箱带来的问题

    1.程序的性能

    由于装箱会隐式地创建对象创建,因此千万不要在一个循环中进行自动装箱的操作,下面就是一个循环中进行自动装箱的例子,会额外创建多余的对象,增加GC的压力,影响程序的性能:

    Integer sum = 0;
     for(int i=0; i<1000; i++){
       sum+=i;
    }

    2.空指针异常

    注意拆箱过程中可能产生的空指针异常,一个简单的例子:

    Object obj = null;
    int i = (Integer)obj;

    3.对象相等比较时

    先来看一个常见的例子:

    Integer a = 120;
    int b= 120;
    Integer c = 120;
    Integer d = new Integer(120);
    System.out.println(a == b);   //true    t1
    System.out.println(a == c);   //true    t2
    System.out.println(a == d);   //false   t3
    
    Integer e = 128;
    Integer f = 128;
    System.out.println(e == f);   //false    t4

    返回结果是不是出乎大家的意料,解释一下每种结果的原因:
    我们先反编译一下生成字节码:

    Integer a = Integer.valueOf(120);
    int b = 120;
    Integer c = Integer.valueOf(120);
    Integer d = new Integer(120);
    System.out.println(a.intValue() == b);
    System.out.println(a == c);
    System.out.println(a == d);
    
    Integer e = Integer.valueOf(127);
    Integer f = Integer.valueOf(127);
    System.out.println(e == f);
    
    Integer e1 = Integer.valueOf(128);
    Integer f1 = Integer.valueOf(128);
    System.out.println(e1 == f1);

    可以看到变量a、c在初始化的时候编译器调用了valueOf进行自动装箱,在a==b时对变量a调用了intValue()方法进行了自动拆箱操作,这就很好解释t1~t4的结果了。

    t1产生的原因是编译器编译时会调用intValue()自动的将a进行了拆箱,结果肯定是true;
    t2跟t4的结果比较难理解:这是因为初始化时,编译器会调用装箱类的valueOf()方法,查看jdk的源码:

    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);
    }

    发现jdk对-128~127之间的值做了缓存,对于-128~127之间的值会取缓存中的引用,通过缓存经常请求的值而显著提高空间和时间性能。
    这就能解释t2结果返回true,而t4由于128不在缓存区间内,编译器调用valueOf方法会重新创建新的对象,两个不同的对象返回false。

    t3结果无论如何都不会相等的,因为new Integer(120)构造器会创建新的对象。

    Byte、Short、Integer、Long、Char这几个装箱类的valueOf()方法都会做缓存,而Float、Double则不会,原因也很简单,因为byte、Short、integer、long、char在某个范围内的整数个数是有限的,但是float、double这两个浮点数却不是。

    展开全文
  • 加入qq群,与博主共享知识库:778444458;...今天在学习Effective Java第2版书时看到了一个实例:首先说下基本类型(如long,int,double)和装箱基本类型(Long,Int,Double);具体情况可看图 ...

     

    今天在学习Effective Java第2版书时看到了一个实例:首先说下基本类型(如long,int,double)和装箱基本类型(Long,Int,Double);具体情况可看图

     

    展开全文
  • java基本类型和包装类型

    千次阅读 2018-10-08 11:20:21
    java是面向对象的语言为什么还要有基本类型,只有包装类型完全面向对象不行吗? java语言可以只有基本类型吗,为什么还有要包装类型? java中的基本类型和包装类型:  基本类型  包装器类型 boolean ...
  • Java 基本类型与引用类型

    千次阅读 多人点赞 2019-03-27 20:55:51
    Java 基本类型与引用类型 一、基本数据类型 java 中一共分为 8 种基本数据类型:byte、short、int、long、float、double、char、boolean, 其中 byte、short、int、long 是整型。float、double 是浮点型,char 是...
  • 基本类型和字符串互相转换

    万次阅读 2021-02-26 16:24:37
    基本数据类型转换成字符串 将字符串转换成基本数据类型
  • TypeScript基本类型总结

    万次阅读 多人点赞 2019-07-11 16:34:16
    基本类型 布尔值 let isDone: boolean = false; 数字 和JavaScript一样,TypeScript里的所有数字都是浮点数。 这些浮点数的类型是number。 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中...
  • 基本类型 1.1.整型int 1.2.实型(浮点型) 1.3.字符型char 二.构造类型 2.1.数组类型[] 2.1.1.字符数组 2.1.2.一维数组 2.1.3.二维数组 2.1.4.三维数组 2.2.结构体类型struct 2.2.1.定义 2.2.2.结构体变量...
  • Java基本数据类型转换与java基本类型转换优先级转换类型1. 自动类型转换: 编译器自动完成类型转换,不需要再程序中编写代码转换规则: 从存储范围小的类型到存储范围大的类型具体规则 : byteàcharàshortàintàlong...
  • Java八大基本类型详解

    千次阅读 多人点赞 2020-03-27 14:52:59
    Java有八大基本类型,其中包括4个整数类型,2个浮点类型,有个字符类型,1个布尔类型
  • 基本类型和引用类型区别

    千次阅读 2018-06-01 14:30:53
    1.基本类型和引用类型在内存中的保存 Java中数据类型分为两大类,基本类型和对象类型。相应的,变量也有两种类型:基本类型和引用类型。 基本类型的变量保存原始值,即它代表的值就是数值本身; 而引用类型的变量...
  • /**判断一个对象是否是基本类型基本类型的封装类型*/ private boolean isPrimitive(Object obj) { try { return ((Class&lt;?&gt;)obj.getClass().getField("TYPE").get(null))....
  • java包装类型作用,和基本类型区别

    千次阅读 2018-09-18 14:27:00
    答案是包装类型的出现是为了方便对基本类型进行操作。包装类型可以解决一些基本类型解决不了的问题,如下: 1.集合不允许存放基本类型数据,只能存放引用类型数据,比如包装类型。以List为例,大家都知道一个动态...
  • js基本类型与引用类型

    千次阅读 多人点赞 2018-06-15 11:21:22
    1.基本类型:Underfined ,Null, Boolean,Number,String2.引用类型: Object首先了解一个概念:栈内存与堆内存---这是两种不同的内存分配方法一般代码逻辑,简单变量,结构体都是放在栈中;而对象,以及被装箱的数据...
  • mybatis3.2.6+spring4.0.2 关于传入基本参数类型 以及多个基本类型参数的问题最近再练习框架,找到了一点心得分享出来,不对之处欢迎提出共勉1 参数类型string 一个参数方法:User getUserByName(String username);...
  • java引用类型和基本类型的比较

    千次阅读 2017-07-18 23:37:24
    引用类型和基本类型的分类,不在写了,网上有很多。我们知道: 当两个基本类型使用”==”比较时,他们比较的是值。 当两个引用类型使用”==”比较时,他们比较的是地址。 当两个引用类型使用方法equals()比较时,...
  • 基本类型和包装类之间的转换基本类型和包装类之间经常需要互相转换,以 Integer 为例(其他几个包装类的操作雷同哦):在 JDK1.5 引入自动装箱和拆箱的机制后,包装类和基本类型之间的转换就更加轻松便利了。...
  • 包装类和基本类型

    万次阅读 多人点赞 2019-03-06 09:18:53
    什么是包装类 所谓包装类,就是能够直接将简单类型的变量表示为一个类,在执行变量类型的相互转换时,我们会大量使用这些包装类。 包装类 ...基本类型与包装类型的区别1、在Java中,一切皆对象,...
  • 基本类型,或者叫做内置类型,是JAVA中不同于类的特殊类型。它们是我们编程中使用最频繁的类型。java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为变量的初始化。 1. Java的简单类型及其...
  • Javascript中的基本类型和引用类型

    千次阅读 2016-06-30 21:46:27
    一、基本类型和引用类型概述 js中数据类型的值包括:基本类型值和引用类型值 基本数据类型:undefined;null;boolean;number;string 引用类型值:保存在内存中,js不允许直接访问内存位置,因此时操作引用而不是...
  • java基本类型和包装类型的区别

    千次阅读 2019-02-24 14:01:29
    1、为什么存在基本类型: 在Java中正常应该设置对象,然后通过new一个对象存储在堆中,再通过栈的引用来使用对象,但对于简单的小的变量,用new 显的繁琐麻烦,所以产生了基本类型 2、有了基本类型,为什么还会产生...
  • js基本类型与引用类型的区别

    千次阅读 2017-06-08 20:27:32
    首先JavaScript中的变量分为基本类型和引用类型。基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象。 1、基本类型 基本类型有Undefined、Null、Boolean、Number 和String。...
  • 基本类型和包装类的区别

    万次阅读 2018-03-24 16:02:52
    因为栈的效率更高,所以保留了基本类型。 2.包装类是对象,拥有方法和字段,对象的调用是引用对象的地址。 3.基本类型是值传递,包装类是引用传递。 4.向ArrayList,LinkedList中放数据的时候,只能放Object...
  • 基本类型的包装类对象使用 == 和 equals进行比较的结果 1、值不同,使用==和equals比较都返回false 2、值相同 使用==比较: 基本类型基本类型基本类型-包装对象返回true 包装对象-包装对象返回...
  • Java基本类型和包装类型总结

    万次阅读 多人点赞 2017-07-19 12:36:40
    1.Java的基本类型及其对应的包装器类Java有8种基本类型:大致分为3类:字符,布尔,数值类型(在java中数值是不存在无符号的,这一点不像C/C++,他们的取值范围是固定的,不会随着机器硬件的环境或者操作系统的改变...
  • Java中基本类型和引用类型的区别

    千次阅读 2019-06-22 18:18:00
    Java中基本类型和引用类型的区别 一、基本数据类型: byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0 short:短整型,在内存中占16位,即2个字节,取值范围-32768~32767,...
  • 数据的基本类型有哪些

    万次阅读 2018-07-05 09:47:24
    Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。byte:byte 数据类型是8位、有符号的,以二进制补码表示的整数;最小值是 -128(-2^7);最大值是 127(2^7-1...
  • Java八种基本类型(byte、short、int、long、浮点数、char、boolean、基本类型转换)
  • java基本类型和封装类型区别及应用

    千次阅读 2019-01-03 15:11:08
    1.基本类型只能按值传递,而每个基本类型对应的封装类是按引用传递的。  2.从性能上说java中的基本类型是在堆栈上创建的,而所有的对象类型都是在堆上创建的,(对象的引用在堆栈上创建)。比如  Integer i=new ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,989,837
精华内容 1,195,934
关键字:

基本类型