【Java 基础】包装类型

1 了解包装类型

1.1 介绍

在 Java 中, 数据类型总共可以分为2大类 : 基础数据类型引用数据类型
基础数据类型并不支持面向对象编程, 因为基础数据类型不具备 “对象” 的特性 – 携带属性和方法。
所以 Java 为 8 种基础数据类型提供了对应的类, 他们就是包装类, 侧面的将基础数据类型变为类, 符合面向对象编程。
之所以没有一开始就是提供包装类, 而是使用基础数据类型, 个人认为只是为了迎合人类根深蒂固的习惯, 并的确能简单、有效地进行常规数据处理。
总的来说:包装类就是基础数据类型在面向对象中的体现。

1.2 包装类型的种类

基本数据类型对应的包装类
byte (1 字节)java.lang.Byte
short (2 字节)java.lang.Short
int (4 字节)java.lang.Integer
long (8 字节)java.lang.Long
char (2 字节)java.lang.Character
float (4 字节)java.lang.Float
double (8 字节)java.lang.Double
boolean (未定)java.lang.Boolean

在 Java boolean 的大小, 有三种说法 1/8字节, 1字节, 4个字节

1.3 Java 代码中的继承关系

Alt '包装类的继承关系'

可以看出他们都实现了 Comparable 接口, 支持进行比较。
同时数字类型的包装类继承了 Number 抽象类, 支持转为其他基础数据类型。

2 装箱/拆箱

在 Java 中, 我们可以无缝的在包装类型和基础数据类型之间切换, 之间是有一个装换过程的, 这个过程就是 装箱/拆箱

// jdk5 之前, 我们如果需要将一个基础数据和包装类型切换, 需要手动处理

int m = 500;
// 手动装箱
Integer obj = new Integer(m);  
// 手动拆箱
int n = obj.intValue();

// jdk5 后支持自动装箱和拆箱

// 自动装箱, 实质是调用 对应包装类.valueOf() 方法实现的
Integer obj = m;
// 自动拆箱, 实质是调用 对应包装类.xxxValue()方法实现的, 其中的xxx 就是对应的数据基础数据类型
int n = obj;

3 包装类型的缓存问题

从装箱和拆箱, 我们可以知道, 把一个基础数据类型转为对应的包装类型, 有 2 种方式

// 主动装箱
Integer num = new Integer(1);
// 自动装箱
Integer num = 1;

这2种方式, 虽然都能达到将一个基础数据类型转为包装类型, 但是他们内部的实现, 还是有很大的区别, 这个区别很多时候, 能被用到很多面试题上。

手动装箱

public class Integer {

  // 内部还是通过一个基础数据类型存储我们的数据值的
  private final int value;

  public Integer(int value) {
    this.value = value;
  }
}

从 Integer 的源码我们可以知道, 我们每次手动装箱, 都会创建一个新的 Integer 对象。

自动装箱

public class Integer {

  /** 自动装箱 会调用到这个方法 */
  public static Integer valueOf(int i) {
      // 从这3行的 逻辑和 变量名 我们可以推测出
      // 如果我们 装箱的值  Integer缓存的下限 <= i <= Integer缓存的上限, 那么他会从 Interger的缓存里面取出对应的包装类, // 否则就重新创建一个新的
      // 那么 Integer的上下限分别是多少呢, 这个就需要看到 IntegerCache的代码了
      if (i >= IntegerCache.low && i <= IntegerCache.high)
          return IntegerCache.cache[i + (-IntegerCache.low)];
      return new Integer(i);
  }

  /** Integer 内部的缓存 */
  private static class IntegerCache {

      static final int low = -128;
      static final int high;
      static final Integer cache[];

      private IntegerCache() {}

      static {
        int h = 127;
        // 读取启动命令行 里面的 java.lang.Integer.IntegerCache.high 配置的值
        // 可以通过控制应用启动时, Integer 内部缓存池的大小
        String integerCacheHighPropValue =  sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");

        if (integerCacheHighPropValue != null) {
          try {
              int i = parseInt(integerCacheHighPropValue);
              // 从配置的值和127中取大的那一个
              i = Math.max(i, 127);

              // 控制 h 的值 小于等于 Integer.MAX_VALUE - 129
              // 这里说一下, h 和 high 都是 int 声明的, 所以最大值为 Integer.MAX_VALUE
              // 同时为了避免下面的(high - low) + 1 = high + 128 + 1 经过运算后超过了 int 的最大值, 变为负数, 所以此处才需要控制 h 的最大上限为  Integer.MAX_VALUE - 129
              h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
          } catch( NumberFormatException nfe) {
          }
        }

        high = h;
        cache = new Integer[(high - low) + 1];
        int j = low;
        // 创建 一个 缓存数组 存放 -128 到 h
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
        assert IntegerCache.high >= 127;
      }
  }
}
  1. 从 Integer 的源码 可以知道, Integer 内部维护了一个Integer的缓存, 这个缓存默认为 -128 到 127 之间, 所以我们通过自动装箱创建的 Integer 并且值在这个区间内, 都是从缓存里面获取到的
  2. 同时我们可以在我们程序启动时, 指定参数 java.lang.Integer.IntegerCache.high = 你想要设置的缓存上限, 修改我们的 Integer 缓存池的上限
  3. 几个数值包装类型, 除了有精度的 Float 和 Double 外都有对应的缓存, 都是 [-128, 127] 之间, 但是只要 Integer 支持配置

4 面试题

// 第一, 比较的是否为同一个对象
Integer num01 = new Integer(1);
Integer num02 = 1;
int num03 = 1;
// false  2 个对象 == 比较的是 2 个对象的内存地址是否一样
System.out.println(num01 == num02);  
// ture  基础数据类型 和 包装类型 比较时, 之间比较数值大小
System.out.println(num02 == num03);
 // true
System.out.println(num01 == num03);


// 第二, 比较的是 缓存, 自动装箱 数值默认在 [-128, 127] 之间都是从缓存取对象, Integer num04 = 2;
Integer num05 = 2;
// true
System.out.println(num04 == num05);

Integer num06 = 128;
Integer num07 = 128;
// false
System.out.println(num06 == num07);


// 第三, 包装类型进行运算后, 会被转为 基础数据类型
Integer  num08 = 1;
Integer  num09 = 2;
Long num10 = 3L;
// true, num08 + num09 变成了数值 3, 此处比较的是数值大小
System.out.println(num10 == (num08 + num09));
// false, equals 比较的是 2 个对象是否一样, 基础数据类型是无法比较的, 所以此处自动装箱了
System.out.println(num10.equals(num08 + num09));

// 第四:低精度和高精度运算, 低精度换转为高精度, 再进行运算
Integer  num11 = 1;
Long  num12 = 2L;
Long num13 = 3L;
// 这里运算后 结果为 3L, 自动装箱为 3, 同时有缓存, 所以 2 个一样
System.out.println(num13.equals(num11 + num12));

// 第五: Double 和 Float 的自动装箱没有缓存
Double num14 = 1D;
Double num15 = 1D;
System.out.println(num14 == num15);

5 总结

包装类型的知识就这些吧, 在判断 2 个对象是否一样时, 基本可以从下面入手

  1. 比较的是数值, 还是对象, 存在自动装箱和自动拆箱
  2. 比较的是包装类型, 是否自动装箱了, 值超过了缓存
  3. 包装类型进行了运算, 默认运算后的结果是基础数据类型
  4. 低精度和高精度运算, 低精度换转为高精度
  5. Double 和 Float 的自动装箱没有缓存
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java中的包装数据类是用来将基本数据类转换为对象的类包装类有两种子类:对象包装类和数值包装类。对象包装类包括Character和Boolean,而数值包装类包括Byte、Short、Integer、Long、Float和Double。\[2\] 在Java中,基本数据类包装类之间可以通过装箱和拆箱操作进行转换。装箱操作是将基本数据类转换为包装类,可以使用包装类的构造方法来接收基本数据类的变量。而拆箱操作是从包装类中取出被包装的数据,可以使用从Number类继承而来的xxxValue方法来完成。\[3\] 例如,可以使用Integer类的构造方法将int类的数据装箱为Integer对象,然后使用intValue方法将Integer对象拆箱为int类的数据。下面是一个示例代码: ```java Integer obj = new Integer(10); int num = obj.intValue(); System.out.println(num); ``` 这段代码将整数10装箱为Integer对象,然后将Integer对象拆箱为int类的数据,并输出结果为10。\[3\] #### 引用[.reference_title] - *1* [Java包装类](https://blog.csdn.net/weixin_46140377/article/details/123404981)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [JAVA基础编程——基本数据类包装类](https://blog.csdn.net/SAKURASANN/article/details/124647622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值