java中的8种基本数据类型:boolean byte char short int float double long

自动拆装箱的问题引入:

由于在一开始学习java的时候,”万物皆对象“这种面向对象的看问题方式,时刻围绕在脑海中。因为静态的变量和基本数据类型不属于对象,但是由8种基本数据类型的自动装拆箱解决了基本数据类型不是对象。

在jdk1.5中引入了自动拆装箱的新特性,在jdk1.5之前,我们想要使用integer类中的方法,我们先要把int变量变成integer类型,可以通过new Integer(intNumber) 或者调用Integer.valueOf(intNumber)方法

自动装拆箱何时发生?

1、在调用方法时把基本数据类型作为参数,但是参数的类型是基本数据类型的包装类时。

在学习过javaSe基础之后,我们知道通过使用集合框架ArrayList或者Map来添加元素的时候,添加的是Object对象,在这里引入ArrayList.add()的源码:

/**

* Appends the specified element to the end of this list.

*

* @param e element to be appended to this list

* @return true (as specified by {@link Collection#add})

*/

public boolean add(E e) {

ensureCapacity(size + 1); // Increments modCount!!

elementData[size++] = e;

return true;

}

1

2

3

4

5

6

7

8

9

10

11

对于源码的解读:首先我们来看看参数中的(E e),为什么是E ?而不是Object?因为E代表的是元素(集合中存储的是元素),我们平时在泛型中可以看到 > ,T 代表的是Type 类,再比如键值对中的Map,K 表示的是Key,V 表示的是Value。E K V 等泛型在使用该参数之前就已经限定好了类型,如果赋值给Object的话,就不用再进行强制类型转换了。

首先把数组的长度+1,这个操作会导致modCount加一,这个变量的作用就是记录当前数组被操作的次数,然后直接把参数传进来的对象赋值给上一次长度位置的元素。返回true表示添加成功

当我们调用ArrayList.add()方法的时候,可以直接调用

ArrayList arrayList = new ArrayList();

arrayList.add(10);

1

2

我们反编译这段代码:

public class AutoboxingTest

{

public AutoboxingTest()

{

}

public static void main(String args[])

{

ArrayList arrayList = new ArrayList();

arrayList.add(Integer.valueOf(100));

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

可以看到,编译器在编译的时候,检测到arrayList.add()需要的是Integer对象,所以把int类型自动装箱成Integer类型。

2、 给基本数据类型的包装类赋值为基本数据类型的时候。

我们还是以Integer和int类型的变量作为例子:

public class AutoboxingTest2 {

public static void main(String[] args) {

Integer integer = 10;

}

}

1

2

3

4

5

6

7

继续反编译例子:

public class AutoboxingTest2

{

public AutoboxingTest2()

{

}

public static void main(String args[])

{

Integer integer = Integer.valueOf(10);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

什么时候自动装箱不起作用?

当我们要调用的方法中存在重载的时候,即基本类型数据作为唯一参数的方法与该基本类型包装类作为唯一参数的方法重载,这时候自动装箱不起作用。

例子:

public class InvalidateAutoboxing {

public void print(int num) {

System.out.println("i am int !");

}

public void print(Integer num) {

System.out.println("i am integer!");

}

}

public class InvalidateAutoboxingTest {

public static void main(String[] args) {

InvalidateAutoboxing invalidateAutoboxing = new InvalidateAutoboxing();

invalidateAutoboxing.print(5);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

运行结果:

这里写图片描述

使用自动装箱拆箱需要注意的地方:

1、循环与自动装箱拆箱

public class CirculateAndAutoboxingAndAutounboxing {

public static void main(String[] args) {

Integer sum = 0;

for (int i = 0; i < 200; i++) {

sum += i;

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

反编译:

public class CirculateAndAutoboxingAndAutounboxing

{

public CirculateAndAutoboxingAndAutounboxing()

{

}

public static void main(String args[])

{

Integer sum = Integer.valueOf(0);

for(int i = 0; i < 200; i++)

sum = Integer.valueOf(sum.intValue() + i);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

反编译代码解读:由于sum是Integer类型,但是sum+=i 需要sum先自动拆箱成int类型(调用intValue()方法),进行相加之后,再自动装箱成Integer类型把结果赋给sum。

Integer.valueOf源码解析:

/**

* Returns a Integer instance representing the specified

* int value.

* If a new Integer instance is not required, this method

* should generally be used in preference to the constructor

* Integer(int), as this method is likely to yield

* significantly better space and time performance by caching

* frequently requested values.

*

* @param i an int value.

* @return a Integer instance representing i.

* @since 1.5

*/

public static Integer valueOf(int i) {

final int offset = 128;

if (i >= -128 && i <= 127) { // must cache

return IntegerCache.cache[i + offset];

}

return new Integer(i);

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

首先我们在源码说明中看到了该构造器缓存经常使用的数据以减少内存的使用和提高效率,Integer把缓冲区的上限脚标设置成128,如果传进来的数据i在-128~127之中,直接返回缓冲区中的IntegerCache.cache[i + 128] 位中的元素

IntegerCache的源码解读:

private static class IntegerCache {

private IntegerCache(){}

static final Integer cache[] = new Integer[-(-128) + 127 + 1];

static {

for(int i = 0; i < cache.length; i++)

cache[i] = new Integer(i - 128);

}

}

1

2

3

4

5

6

7

8

9

10

IntegerCache是Integer的内部类,并且内部数组的上限为256元素,在这个内部类中使用了静态代码块(在类加载的时只执行一次),把-128~127都缓存在数组中。所以以后调用的时候就可以直接返回Integer对象,而不用return new Integer(i); Integer Short Long的缓冲数组是一样的,但是Character的范围为0~127,Double和Float没有缓冲数组

话又说回来,刚刚我们在分析循环与自动装拆箱的使用需要注意:当参与的数值不在缓存的范围内,会产生大量的对象,这样会产生很多垃圾对象,增加GC的工作压力。

2、自动装拆箱与三元运算符造成的空指针异常(NPE)

public class AutounboxingWithConditionalOperator {

public static void main(String[] args) {

HashMap hashMap = new HashMap();

Boolean b = (hashMap != null ? hashMap.get("test") : false);

}

}

1

2

3

4

5

6

7

8

9

10

运行:

这里写图片描述

发生了空指针异常

如果在Map中添加了test这条数据:

public class AutounboxingWithConditionalOperator {

public static void main(String[] args) {

HashMap hashMap = new HashMap();

hashMap.put("test", true);

Boolean b = (hashMap != null ? hashMap.get("test") : false);

System.out.println(b);

}

}

1

2

3

4

5

6

7

8

9

10

运行:

这里写图片描述

我们再反编译刚刚NPE异常的代码:

public class AutounboxingWithConditionalOperator

{

public AutounboxingWithConditionalOperator()

{

}

public static void main(String args[])

{

HashMap hashMap = new HashMap();

Boolean b = Boolean.valueOf(hashMap == null ? false : ((Boolean)hashMap.get("test")).booleanValue());

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

下面是hashMap.get(key)方法的说明:

Returns the value to which the specified key is mapped,

*or null if this map contains no mapping for the key.

由上面可以看出,由于Map.get(key)方法,如果没有指定的数据,返回的是null。

再由于三元运算符有如下定义:

The type of a conditional expression is determined as follows:

1、If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

2、If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

3、If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.

译文:

三元运算符的类型由以下情况决定:

1、如果第二和第三个操作结果拥有同样类型(这个类型可能为null),那么这个类型就是该三元运算符的结果类型

2、如果第二个操作和第三个操作结果其中一个的结果类型为基本数据类型,另外一个操作结果为可以装箱转换成与前面一种类型一致的包装类,那么这个三元运算符的运算结果类型为基本数据类型,即把包装类拆装。

3、如果在第二、三个操作结果中,有一个为null类型,另外一个为引用类型,那么这个三元运算符的表达式为引用类型。

综上所述,对于上面出现的情况,对于一个操作结果为基本类型,另外一个为包装类型的三元运算符表达式来说,为了避免NEP的产生,可以通过把它们变成同样类型(参考三元运算符定义的第一条)。

参考资料:

Conditional Operator ? :

Boxing Conversion

The Java™ Tutorials about Autoboxing and Unboxing

What is Autoboxing and Unboxing in Java

Java中的自动装箱与拆箱

要裝箱還是拆封

4.2 自動裝箱、拆箱

Java 自动装箱和拆箱

Java泛型中K T V E ? object等的含义

自动拆箱导致空指针异常

java支持的数据类型有哪些_Java支持的数据类型有哪些?什么时候自动装拆箱?...相关推荐

  1. java 自动装拆箱

    title: "java 自动装拆箱" tags: Java 将基本数据类型封装成对象的过程叫做装箱(boxing),反之基本数据类型对应的包装类转换为基本数据类型的过程叫做拆箱( ...

  2. java unbox_java base-05-Box UnBox 自动装拆箱

    java 语言的设计 java 为什么有基本类型 作为一门 OO 语言,java 为什么要保留基本类型呢. 个人的理解是,出于工程学上的考虑. 基本类型的内存占用,比对象要小得多. 基本对象 基本数据 ...

  3. java基础(八) 深入解析常量池与装拆箱机制

    ###引言 本文将介绍常量池 与 装箱拆箱机制,之所以将两者合在一起介绍,是因为网上不少文章在谈到常量池时,将包装类的缓存机制,java常量池,不加区别地混在一起讨论,更有甚者完全将这两者视为一个整体 ...

  4. java自动封箱_Java程序员面试,自动封箱/拆箱原理与包装类的缓冲机制你知道么?(转)...

    概述 本文中小编为大家细致的讲解了Java中基本数据类型对应的包装类以及包装类的缓冲机制在实际开发中的应用 . 并且对Java中基本数据类型的包装类的主要应用---自动封箱.自动拆箱做了底层剖析 . ...

  5. Java包装类与基本数据类型的自动 手动装箱与自动 手动拆箱

    Java包装类与基本数据类型的自动 手动装箱与自动 手动拆箱 **自动装箱与拆箱**,实现代码如下: /*** 装箱 : 基本数据类型-----> 包装类* 拆箱: 包装类-------> ...

  6. Java八种基本数据类型的大小,以及封装类,自动装箱/拆箱的用法?

    参考:http://blog.csdn.net/mazhimazh/article/details/16799925 1. Java八种基本数据类型的大小,以及封装类,自动装箱/拆箱的用法? 原始类型 ...

  7. java 自动拆箱_Java中的自动装箱拆箱

    Java中的自动装箱拆箱 一.自动装箱与自动拆箱 自动装箱就是将基本数据类型转换为包装类类型,自动拆箱就是将包装类类型转换为基本数据类型. 1 //自动装箱 2 Integer total = 90; ...

  8. Java自动装箱/拆箱 - Java那些事儿

    昨天Java基本数据类型和引用类型一文中漏了几张图,已经补上,需要的自己回头去看,本系列文章首发于公众号:saysayJava. 在让人疑惑的Java代码 - Java那些事儿 一文中我们说到编译器自 ...

  9. java基础--06(自动装箱拆箱)

    目录 1.自动装箱,自动拆箱 1.自动装箱,自动拆箱 装箱就是自动将基本数据类型转换为包装器类型:拆箱就是 自动将包装器类型转换为基本数据类型. java的数据类型: 自动装箱: 最主要的就是Inte ...

最新文章

  1. Windows注册文件类型信息的学习心得
  2. windows文件路径 正则表达式_Windows非常实用的四款软件
  3. VUE.js 中取得后台原生HTML字符串 原样显示问题
  4. php输入安全验证漏洞,PHP 输入验证错误漏洞
  5. linux防火墙策略文件夹,Linux防火墙iptables的策略
  6. Python——pip安装报错:is not a supported wheel on this platform
  7. python 基础列表解析(十八)
  8. NOIP2018 游记
  9. 【面试】基于二叉树层次遍历相关问题的求解
  10. 系统学习深度学习(三十)--BiLSTM
  11. C#——NotifyICON的使用
  12. DSP2812之定时器
  13. h5前端兼容性问题及解决方法集合
  14. 机器学习——建筑能源得分预测
  15. 信息搜集工具:Maltego
  16. Spring Security 官方文档学习路径
  17. php faker,faker php伪造填充数据
  18. 树状数组 之 poj 3067
  19. isset与empty的区别
  20. Axure AxureRP9 密钥

热门文章

  1. 使用Java快速入门的Apache Thrift
  2. Arquillian 1.0.0.Final正式发布! 准备使用GlassFish和WebLogic! 杀死所有虫子!
  3. 零XML的Spring配置
  4. 常见花材的固定的方法有哪些_旋流器常见的故障及处理方法有哪些?
  5. Windows下Maven的下载、安装及IntelliJ IDEA集成配置
  6. 大学计算机系学生,大学计算机专业学生自我介绍
  7. java算术运算符的分类_6.Java算术运算符
  8. 苹果录屏功能没有声音_其实苹果手机也有录屏功能!简单操作几步,就能轻松开启...
  9. micropython stm32f030_24C02 读写代码,基于STM32F030
  10. python内置类型_Python内置对象类型