美文网首页
Java基本类型的包装类

Java基本类型的包装类

作者: cornprincess | 来源:发表于2020-04-02 15:49 被阅读0次

There are two kinds of types in the Java programming language: primitive types (§4.2) and reference types (§4.3). There are, correspondingly, two kinds of data values that can be stored in variables, passed as arguments, returned by methods, and operated on: primitive values (§4.2) and reference values (§4.3). [1]

通过java官方语言规范(Java SE Language Specification)的描述我们可以知道,目前Java语言所使用的数据类型有两种:PrimitiveTypeReferenceType

PrimitiveType:
{Annotation} NumericType
{Annotation} boolean
NumericType:
IntegralType
FloatingPointType
IntegralType:
(one of)
byte short int long char
FloatingPointType:
(one of)
float double

设计包装类的原因

其中PrimitiveType共有byte, short, int, long, char, float, double, boolean八种,但是这八种基本类型都有对应的包装类(wrapper),Java语言在设计时为什么会需要这八种包装类呢?我认为根本的原因在于Java是面向对象的语言,使用对象进行编程可以最大程度发挥面向对象的优势。

[图片上传失败...(image-e3df1-1585813540458)]

集合类泛型只能支持对象

List<Integer> list = new ArrayList<Integer>(); 

由于每个值分别包装在对象中,所以 ArrayList<Integer> 的效率要低于 int[] ,因此,应该用包装类构建小心集合

基本类型不能被赋值null

在写有些业务代码时需要用到null,此时需要使用包装类

int a = 0;
Integer A = null;
Integer B = 2 * A; // Throw NullPointException

但是此时需要注意可能会抛 NullPointException 异常。

Integer a = 1;
Double b = 2.0;
System.out.println(true ? a : b); // 1.0

如果在一个条件表达式中用到了 Integer 和 Double 类型,那么Integer值会先拆箱,提升为 double,再装箱为 Double。

java.util包中不支持基本类型操作

对于 基本类型常用的方法,除了可以放在 util 包中,还可以放在包装类中, 如 Integer.parseInt() 静态方法。

自动拆装箱

JDK5中引入了自动拆装箱技术[2]

// autoBoxing
list.add(3);
list.add(Integer.valueOf(3)); 

Integer t = 1;
t++;

// autoUnBoxing
int n = list.get(i);
int n = list.get(i).intValue();

包装类常量池

在JDK5中引入了包装类的常量池[3],类似String类的对象池机制一样,用于节约内存以及提高运行的效率。

通过查看源码我们可以知道,Byte, Short, Integer, Long, Character,这五个包装类存在常量池,并且有以下两点需要注意:

  • 常量池的范围为[-128, 127]
  • 常量池只对自动装箱定义的包装类对象有效,对构造函数生成的包装类对象无效。

自动装箱示例

Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood

自动装箱过程是由编译器自动完成的。

代码示例

@Test
public void test() {
  Integer i = 127;
  Integer i2 = 127;
  System.out.println(i  == i2); // true

  Integer i3 = -128;
  Integer i4 = -128;
  System.out.println(i3  == i4); // true

  Integer i5 = 128;
  Integer i6 = 128;
  System.out.println(i5  == i6); // false

  Integer i7 = -129;
  Integer i8 = -129;
  System.out.println(i7  == i8); // false

  Integer j = new Integer(127);
  Integer j2 = new Integer(127);
  System.out.println(j == j2);  // false
}

这里最后一个测试用例输出 false 可以由以下源码得到答案,简单来说通过构造器生产的包装类对象不会从常量包装类缓存中取,每次都是新生成的,所以不同。

Integer中常量池源码(JDK1.8.0_202)解读

/**
    * 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=<size>} 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;
  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) {
    try {
      int i = parseInt(integerCacheHighPropValue);
      i = Math.max(i, 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;
  }

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

我们从源码的注释中可以看到 // range [-128, 127] must be interned (JLS7 5.1.7), 默认的范围为 [-128, 127], 并且JDK6之后,我们可以通过 VM argument -XX:AutoBoxCacheMax=size 来改变最大值

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

JLS7 5.1.7

关于常量池范围总结:Byte, Short, Integer, Long都是[-128, 127],Character为[0, 127],并且这五个包装类只有Integer是可以自定义最大值范围的。

欢迎大家来github相关仓库提issue

Reference

  1. The Kinds of Types and Values
  2. Autoboxing and Unboxing
  3. Java Integer Cache
  4. Java核心技术·卷 I(原书第10版)

相关文章

  • 第47节:Java当中的基本类型包装类

    Java当中的基本类型包装类 01 基本数据类型对象的包装类 什么是基本数据类型对象包装类呢?就是把基本数据类型封...

  • JavaSE进阶五 包装类

    java中的包装类 java中对8种基本数据类型提供了8种包装类型;包装类是引用类型,父类是Object。 为什么...

  • Java 常用类 04. Java 包装类

    包装类 Java 数据类型分为:基本数据类型 和 引用数据类型,但基本数据类型怎么成为对象呢? 包装类:基本数据类...

  • Java中必须了解的常用类

    学习了解# Java中的包装类 Java中基本类型和包装类型之间的转换 Java中基本类型和字符串之间的转换 使用...

  • JAVA中的对象

    java8增强的包装类 java中基本数据类型不能当作对象类型变量使用的问题, java提供了包装类 (Wrapp...

  • 1. Java之基本数据类型

    各个基本数据类型比较 整数的不同进制 包装类以上8种基本类型都不是类,Java 提供了对应的类,称之为包装类。包装...

  • Java中的包装类,以及自动装箱和拆箱

    包装类 由于基本类型只能做一些简单的操作和运算,所以Java又封装了各种基本类型,提供了包装类。 包装类提供了更多...

  • java类型,打印变量类型,类型转换

    java类型 分为两类 基本类型boolean 对应包装类 java.lang.Boolean 类型名称默认值补充...

  • 基本数据类型的包装类

    包装类 Java提供了一组包装类,来包装所有的基本数据类型 以上包装类又分为两种子类型: 对象型包装类(Objec...

  • 五:Java基础入门-基本类型的包装类

    1:基本类型的包装类概述 Java为基本数据类型提供了对应的类,这些类称作包装类。 如下表所示: 2:为什么要使用...

网友评论

      本文标题:Java基本类型的包装类

      本文链接:https://www.haomeiwen.com/subject/wzmxphtx.html