转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10832303.html

一:基本类型与包装类型

    我们知道,Java有8大基本数据类型,4整2浮1符1布。

我们在实际开发中,除了使用到数据的值之外,还会涉及到对数据的操作。根据“面向对象”编程的思想,这些常见的操作被抽象成方法,封装到了一个类中,一个基本数据类型对应一个这样的类,这些类统称为“包装类”。

8大基本类型 分别对应 8个包装类,再加上两个用于高精度运算的包装类,共有10大包装类。分别为:

Byte:对应 byte 类型

Short:对应 short类型

Integer:对应 int类型

Long:对应 long类型

Float:对应 float类型

Double:对应 double类型

Character:对应 char类型

Boolean:对应 boolean类型

BigInteger:支持任意精度[长度]的整数运算。

BigDecmail:支持任意精度的浮点数运算,主要用于金额计算。

包装类的好处:它提供了一系列操作本类型数据的方法,可以为我们在开发过程中操作8大基本类型数据提供充足的“工具”。

二:自动拆装箱

1、装箱

把基本数据类型转换成包装类的过程就是打包装,英文名boxing,翻译为装箱。

2、拆箱

反之,把包装类转换成基本数据类型的过程就是拆包装,英文对应于unboxing,中文翻译为拆箱。

3、自动拆装箱

自动装箱: 就是将基本数据类型自动转换成对应的包装类。
    自动拆箱:就是将包装类自动转换成对应的基本数据类型。

4、自动拆装箱的发生场景

1)自动拆装箱的过程主要发生在赋值操作上:将一个基本数据类型的值符给包装类变量,则进行自动装箱操作;将一个包装类变量的值赋给基本数据类型变量,则发生自动拆箱操作。

2)将基本数据类型放入集合类时:Java中的集合类只能接收对象类型,当我们把基本数据类型放入集合类中的时候,会进行自动装箱成对应的包装类对象后再放入。

3)基本数据变量与包装类变量进行运算操作时:基本数据变量与包装类变量进行比较运算、数学运算、三目运算时,会自动拆箱成基本类型再进行运算。

4)函数返回值自动拆装箱:当函数定义时,指定了函数返回值是包装类,则return 一个基本数据类型值时,就会自动装箱;如果定义的函数返回值是基本数据类型时,return一个包装类对象会自动拆箱。

三:自动拆装箱带来的问题

1、包装对象的数值比较,不能简单的使用==,虽然-128到127之间的数字可以[下文中解释],但是这个范围之外还是需要使用equals比较。【== 比较的是地址,equals比较的是值】

2、由于自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE[null pointer exception]。

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

四:Integer的缓存机制—— -128到127之间的数字自动装箱后的会返回同一个对象。

详情可参阅:Java中整型的缓存机制 这篇文章。

首先看个例子:

package com.javapapers.java;public class JavaIntegerCache {
public static void main(String... strings) { Integer integer1 = 3; //整数3自动装箱
Integer integer2 = 3; //整数3自动装箱 if (integer1 == integer2) //两个自动装箱后对象比较
System.out.println("integer1 == integer2");
else
System.out.println("integer1 != integer2"); Integer integer3 = 300;//整数300自动装箱
Integer integer4 = 300;//整数300自动装箱 if (integer3 == integer4)//两个自动装箱后对象比较
System.out.println("integer3 == integer4");
else
System.out.println("integer3 != integer4"); }}

上面的代码输出的结果是:

integer1 == integer2
integer3 != integer4

也就是说:整数3自动装箱后赋值给a、b两个引用变量,这两个引用指向的是同一个对象。

但是整数300自动装箱后赋值给c、d两个引用变量,这两个引用指向的是不同对象。

那么问题来了——都是自动装箱,为什么不同数值自动装箱的结果不一样呢?——这是由于Integer的缓存机制导致的。

1、为什么要实现Integer的缓存机制呢?

在实际开发过程中,会经常在不经意间就触发了自动拆装箱机制。我们知道,自动装箱会创建一个包装类对象,一套程序跑下来,会生成多少个这样的对象?那开销得多大啊。

因此,出于节省内存和提高性能的目的,从Java5开始,为我们提供了Integer的缓存机制。

2、Integer的缓存机制的生效逻辑

这个缓存机制是怎么工作的呢?我们来看一下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) {
if (i >= IntegerCache.low && i <= IntegerCache.high) //先判断整数值为是否处于IntegerCache.low~IntegerCache.high之间的缓存值
return IntegerCache.cache[i + (-IntegerCache.low)]; //是的话,则从缓存数组中取对应的包装类对象之间返回
return new Integer(i);//否,则创建一个新的包装类对象返回
}

从代码中可以看出,自动装箱时,创建对象之前先从IntegerCache.cache中寻找,如果没找到才使用new新建对象。

IntegerCache 类源码

/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/ private static class IntegerCache {
static final int low = -128; //默认可缓存的最小值是 -128
static final int high; //可缓存的最大值
static final Integer cache[]; //缓存数组 static {
// high value may be configured by property 可缓存最大值可通过jvm参数指定
int h = 127; //默认可缓存最大值为127
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); //从JVM参数中获取可缓存最大值配置
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);//将配置值与127之间取较大值,即:可缓存值最小为127
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1); //可缓存值不能超过整型大最大值
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
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;//断言:可缓存最大值必须大于等于127
} private IntegerCache() {}
}

从上面可以得知,Integer缓存数组中保存了 -128~h(h>=127) 的值的包装类对象,其中h值可以通过JVM参数 -XX:AutoBoxCacheMax=size 修改【这也是JVM调优的一个常用配置项】。

至于最小范围 -128~127 之间,是因为这个范围的数字是最被广泛使用的。

IntegerCache是Integer类中定义的一个private static的内部类,因此在程序中,第一次使用Integer对象的时候会需要一定的额外时间来初始化这个缓存。

3、其他包装类的缓存机制

ByteCache用于缓存Byte对象:固定范围: -128 到 127,不能更改。

ShortCache用于缓存Short对象:固定范围: -128 到 127,不能更改。

LongCache用于缓存Long对象:固定范围: -128 到 127,不能更改。

CharacterCache用于缓存Character对象:固定范围: 0 到 127,不能更改。

举个例子:

如果一个变量p的值是:

-128至127之间的整数

true 和 false的布尔值

‘\u0000’至 ‘\u007f’之间的字符

之间时,将p自动装箱成a和b两个对象,可以直接使用a==b判断a和b的值是否相等。

Java的自动拆装箱与Integer的缓存机制的更多相关文章

  1. Java的自动拆/装箱

    作者:Alvin 关键字:语法糖 类 对象 参考 Java 中的语法糖 语法糖--这一篇全了解 浅谈 Integer 类 什么是Java中的自动拆装箱 深入剖析Java中的装箱和拆箱 前言 我们知道, ...

  2. Java之自动拆装箱

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

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

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

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

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

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

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

  6. Integer的缓存和自动拆装箱

    先看一个简单的例子: public class TestInteger { public static void main(String[] args) { System.out.println(&q ...

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

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

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

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

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

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

随机推荐

  1. zz图像、神经网络优化利器:了解Halide

    动图示例实在太好 图像.神经网络优化利器:了解Halide  Oldpan  2019年4月17日  0条评论  1,327次阅读  3人点赞 前言 Halide是用C++作为宿主语言的一个图像处理相 ...

  2. Spring Cloud微服务安全实战_3-8_API安全之登录

    前面的文章 https://www.cnblogs.com/lihaoyang/p/11967121.html  说了用过滤器实现HttpBasic 认证 ,在请求头里携带用户名和密码,存在的问题是, ...

  3. LeetCode 1257. Smallest Common Region

    原题链接在这里:https://leetcode.com/problems/smallest-common-region/ 题目: You are given some lists of region ...

  4. $O(k^2)$ 求前缀 $k$ 次幂和(与长度无关)

    接下来求解前缀幂次和 求解 \(\sum_{i = 1}^{k} i^k\) \[ \begin{aligned} (p+1)^k - 1 = (p+1)^k - p^k + p^k - (p-1)^ ...

  5. linux下找到JVM占用资源最高的线程

    linux的top命令不仅可以看线程的资源占用,还可以看进程下线程的资源占用,结合对应的java命令可以定位到具体有问题的Java代码,以找出占用CPU最高的线程为例: 第一步: 通过 top命令查找 ...

  6. 【转】Java代码编译过程简述

    转载:https://blog.csdn.net/fuzhongmin05/article/details/54880257. 代码编译是由Javac编译器来完成,流程如下图1所示: 图1 Javac ...

  7. Linux性能优化实战学习笔记:第二十一讲

    一 内存性能指标 1.系统内存使用情况 共享内存:是通过tmpfs实现的,所以它的大小也就是tmpfs使用的大小了tmpfs其实也是一种特殊的缓存 可用内存:是新进程可以使用的最大内存它包括剩余内存和 ...

  8. MySQL实战45讲学习笔记:第二十八讲

    一.读写分离架构 在上一篇文章中,我和你介绍了一主多从的结构以及切换流程.今天我们就继续聊聊一主多从架构的应用场景:读写分离,以及怎么处理主备延迟导致的读写分离问题. 我们在上一篇文章中提到的一主多从 ...

  9. scss 入门基础

    在一个项目中,样式是必不可少的一部分,而对于一个完整的项目来说是有个基准色调的.在项目需求变化不大的情况下,可以直接在css中写这些颜色值之类的东西.但是如果遇到一个朝令夕改的领导或者甲方,那会变得相 ...

  10. WPF 目录树绑定 与 遍历

    定义树节点,(编译环境VS2017) public class GBTreeNode : INotifyPropertyChanged { private string _deviceId = str ...