作者:Alvin

关键字:语法糖  类  对象

参考

Java 中的语法糖

语法糖--这一篇全了解

浅谈 Integer 类

什么是Java中的自动拆装箱

深入剖析Java中的装箱和拆箱

前言

我们知道,Java有8中基本数据类型,分别是byte,short,int,long,char,float,double,boolean,但是定义的这些基本数据类型的值只是一个字面量,而字面量的补码是的的确确存储在内存上的一个量,这个量不具有其他的方法属性。但是我们在编程开发中有把一个整型int转换成字符串等的需求,再如当我们需要把数据放到集合中时,我们的基本数据类型是不允许被放入的,而Java中的中心思想就是对象,所以Java将它们封装成对象Byte、Short、Integer、Long、 Character、Float、Double、Boolean,并给出相应的方法。这样当我们有需求的时候我们就可以通过相对应的对象进行调用方法来解决。

一、案例引入

  1. public static void main(String[] args) {
  2. Integer i = 10;
  3. Integer j = 10;
  4. System.out.println(i == j);
  5.  
  6. Integer a = 128;
  7. Integer b = 128;
  8. System.out.println(a == b);
  9.  
  10. int k = 10;
  11. System.out.println(k == i);
  12. int kk = 128;
  13. System.out.println(kk == a);
  14.  
  15. Integer m = new Integer(10);
  16. Integer n = new Integer(10);
  17. System.out.println(m == n);
  18. }

执行结果

  1. true
  2. false
  3. true
  4. true
  5. false

二、写法分析

在进行分析之前我们先来了解一个概念:语法糖

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

  Java中的语法糖也是新增了一些语法,使得程序员使用更加方便。但是计算机底层还是使用基本语法来实现的。下面我们讨论几个经常使用到的语法糖,可变参数自动装箱/拆箱增强for循环

我们以Integer类为例,在我们用如下代码编写程序后,当使用Javac.exe工具操作之后,编译器会把我们的这个程序重写按照DRY(Don't repeat yourself)原则进行编译

  1. public class Test {
  2.  
  3. public static void main(String[] args) {
  4. Integer num1 = 123;//将一个基本数据类型赋给Integer对象
  5. int num2 = num1;//将一个Integer对象赋给整形变量
  6. }
  7. }

对以上代码编译后的Test.class反编译结果如下

  1. public class Test{
  2. public static void main(String[] args) {
  3. Integer num1 = Integer.valueOf(123);//装箱操作
  4. int num2 = num1.intValue();//拆箱操作
  5. }
  6. }

Java语言中,javac命令可以将后缀名为.java的源文件编译为后缀名为.class的可以运行于Java虚拟机的字节码。如果你去看com.sun.tools.javac.main.JavaCompiler的源码,你会发现在compile()中有一个步骤就是调用desugar(),这个方法就是负责解语法糖的实现的。

可以看到,在Java编译器进行编译的时候会自动把我们的代码重整成符合DRY原则代码并编译成.class文件。在我们定义一个Integer类型的变量后,当我们把整型的值赋值给该Integer类型,实际上在编译后的操作时执行了Integer.valueOf(123);操作,只是我们采用了语法糖写法而简写了方法调用的过程,同理,当把一个Integer的对象用语法糖写法编写的时候,该对象也调用了它的intValue方法进行转换类型。所以我们语法糖写法只是在编写的时候简化了代码,而类型的转换操作在编译器运行的时候会把调用的方法重新补充上。其他的八个基本数据类型各自对应的情况和Integer相同,不再赘述。

其他类似的语法糖写法还有增强for循环(底层还是循环),可变参数,switch对String和枚举的支持等

三、结果分析

了解了上面代码的转换过程,我们从反编译的结果得知:再Java语言中永远遵守不同类型之间不可以进行赋值的规则。置于我们在代码中的编写形式有时只是进行了简写,而最后的执行还要依赖于编译器的解析结果。

四、实现过程

上方就是基本数据类型的自动拆/装箱,他们的装箱遵循以下规则

自动装箱规范要求 byte<= 127、char<=127、-128<=short <=127、-128<=int <=127都被包装到固定的对象中(缓存)。

也就是说在装箱过程中执行valueOf(参数)方法后,如果满足以上条件就会被封装成Integer对象中。valueOf函数如下

从函数可以看出,当在-128到127范围内,会生成同一个对象,在范围之外,会执行new Integer();我们都知道在Java语言中,new一个对象是存储在堆里的,我们通过栈中的引用来使用这些对象;所以,对象本身来说是比较消耗资源的。

五、总结

包装类的应用

1、Java中的集合类只能接收对象类型,而Java通过包装类实现了把基本数据类型放入集合操作的目的。并且在放入集合的时候这种封装时自动完成的。

2、包装类与基本数据类型进行比较运算,是先将包装类进行拆箱成基本数据类型,然后进行比较的。

3、两个包装类型之间的运算,会被自动拆箱成基本类型进行。

4、三目运算符flag ? i : j;片段中,三目运算符的语法规范:当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。如果这个时候i的值为null,那么久会发生NPE。(自动拆箱导致空指针异常

5、函数参数与返回值

6、Integer中的缓存机制有关。在Java 5中,在Integer的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。适用于整数值区间-128 至 +127。只适用于自动装箱。使用构造函数创建对象不适用。当需要进行自动装箱时,如果数字在-128至127之间时,会直接使用缓存中的对象,而不是重新创建一个对象。

另外javadoc详细的说明了缓存支持-128到127之间的自动装箱过程。最大值127可以通过-XX:AutoBoxCacheMax=size修改。实际上这个功能在Java 5中引入的时候,范围是固定的-128 至 +127。后来在Java 6中,可以通过java.lang.Integer.IntegerCache.high设置最大值。

六、注意事项

包装类的使用简化了代码,方便了编程者对数据的操作,实现了面向对象思想,但是也引入了一些麻烦,我们要尽量避免,以防对以后的编程中出现负担。

1、包装对象的数值比较,不能简单的使用==,虽然-128到127之间的数字可以,但是这个范围之外还是需要使用equals比较。

2、如果一个for循环中有大量拆装箱操作,会浪费很多资源。

3、有些场景会进行自动拆装箱,同时也说过,由于自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE。

Java的自动拆/装箱的更多相关文章

  1. Java之自动拆装箱

    顾名思义,自动拆装箱就是将基本类型和包装类进行自动的互相转换. JDK5.0后,将自动装箱/拆箱引Java中. 自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中 ...

  2. Java的自动拆装箱与Integer的缓存机制

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10832303.html 一:基本类型与包装类型     我们知道,Java有8大基本数据类型,4整2浮1符1 ...

  3. 关于java的自动拆装箱若干细节问题

    一.首先需要了解的几个前提: 1.自动装箱过程是通过调用valueOf方法实现的(如Integer.valueOf(10)),而拆箱过程是通过调用包装器的 xxxValue方法实现的(如Integer ...

  4. java中的自动拆装箱与缓存(Java核心技术阅读笔记)

    最近在读<深入理解java核心技术>,对于里面比较重要的知识点做一个记录! 众所周知,Java是一个面向对象的语言,而java中的基本数据类型却不是面向对象的!为了解决这个问题,Java为 ...

  5. 《java入门第一季》之Integer类和自动拆装箱概述

    / * int 仅仅是一个基本类型.int有对应的类类型,那就是Integer.  * 为了对基本数据类型进行更多的操作,更方便的操作,Java就针对每一种基本数据类型提供了对应的类类型--包装类类型 ...

  6. java的数据类型、自动拆装箱、字面量

    java 中的数据类型分为两大类:值类型(基本数据类型)和引用类型(复合数据类型)  值类型分为 1,整数类型(byte,short,int,long) 2,浮点类型(float,double) 3, ...

  7. 一文读懂什么是Java中的自动拆装箱

    基本数据类型 基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型.它们是我们编程中使用最频繁的类型. Java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为 ...

  8. Java枚举、静态导入、自动拆装箱、增强for循环、可变参数

    一.枚举简介 1.什么是枚举? 需要在一定范围内取值,这个值只能是这个范围内中的任意一个 现实场景:交通信号灯,有三种颜色,但是每次只能亮三种颜色里面的任意一个 2.使用一个关键字 enum enum ...

  9. 静态导入方法即自动拆装箱(java)

    package example6;import static java.lang.System.out;import static java.util.Arrays.sort;import java. ...

随机推荐

  1. 初学Linux(一)关闭操作shutdown halt reboot

    1.shutdown –h 10 #这个命令告诉大家,计算机将在10分钟后关机,并且会显示在登陆用户的当前屏幕中. 2.Shutdown –h now #立马关机 3.Shutdown –h 11:1 ...

  2. 【数据结构】 顺序表查找(折半查找&&差值查找)

    #include <stdio.h> #include <stdlib.h> #include <time.h> #define MAXSIZE 10 首先构造一个 ...

  3. 关于php优化 你必须知道的一些事情

    1. 用单引号代替双引号来包含字符串,这样做会更快一些.因为 PHP 会在双引号包围的 字符串中搜寻变量,单引号则不会,注意:只有 echo 能这么做,它是一种可以把多个字符 串当作参数的“函数”(译 ...

  4. Js 运算符(加减乘除)

    1.加法 + +NaN //NaN,有一个为NaN就为NaN var box=Infinity+Infinity //Infinity var box=-Infinity + -Infinity // ...

  5. EventBus轻松使用

    什么是EventBus 由greenrobot组织贡献(该组织还贡献了greenDAO),一个Android事件发布/订阅轻量级框架,功能:通过解耦发布者和订阅者简化Android事件传递,Event ...

  6. 有关linqtosql和EF的区别

    LINQ to SQL和Entity Framework都是一种包含LINQ功能的对象关系映射技术.他们之间的本质区别在于EF对数据库架构和我们查询的类型实行了更好的解耦.使用EF,我们查询的对象不再 ...

  7. 拥抱.NET Core系列:MemoryCache 缓存域(转载)

    阅读目录 MSCache项目 缓存域 写在最后 在上一篇“<拥抱.NET Core系列:MemoryCache 缓存选项>”我们介绍了一些 MSCache 的机制,今天我们来介绍一下 MS ...

  8. 参加360前端星计划总结(二)--HTML&CSS

    HTML学习手册(英文版)html:the living standard 重要知识点 文档声明的作用a. 指定html的文档标准和版本b. 告诉浏览器渲染模式,有怪异模式(较为古老的模式,不写文档声 ...

  9. 关于NSStringFromClass的一点见解

    今天做项目的时候遇到一个需求,就是子view视图弹出时,屏蔽掉父view的所有手势,然后想到用 UIGestureRecognizerDelegate代理方法,中间省一些文字(无奈脸),言归正传,NS ...

  10. 小技巧textbox的行数

    没什么技术含量,但如果不知道则实现起来很麻烦. c#中textbox.lines只记录回车的数量,并不是真正的总行数,如何得到呢,请使用: int 总行数 = this.textBox1.GetLin ...