包装类自动装拆箱缓存数组

Posted zachyoung

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了包装类自动装拆箱缓存数组相关的知识,希望对你有一定的参考价值。

包装类

1、手写包装类

 

 package wrapper;
 ?
 /**
  * 被 final 修饰的类就是所谓的 最终类( 或者称作 不可变/不变类 )
  * 被 final 修饰的类 没有子类
  * 被 final 修饰的变量称作 最终变量 ( 可以是 类变量、实例变量、局部变量、参数 )
  * */
 ?
 public final class Decimal {
 ?
     // 被 final 修饰的 类变量 在初始化之后不能 再次赋值
     // 必须 显式赋值完成初始化
     // 被 final 修饰的 类变量 被称作 【常量】
     public final static long MAX_VALUE = Long.MAX_VALUE; // 常量的名称中 所有单词大写 多个单词之间用 _ 隔开
     public final static long MIN_VALUE = Long.MIN_VALUE;
 ?
     // 被 final 修饰的 实例变量 在初始化之后不能再次赋值
     private final long value;
 ?
     public Decimal(long value) {
         // System.out.println("this.value:" + this.value ); // 失败 未初始化变量
         this.value = value;
         System.out.println("this.value:" + this.value );
    }
 ?
     public long getValue() {
         return value;
    }
     public void setValue() {
         // this.value = value; // 错误 无法为 value 赋值
    }
     public static Decimal valueOf(long value) {
         return new Decimal(value);
    }
 ?
     public static void main(String[] args) {
         // 在 堆内存中所创建的 Decimal 对象是 不可变的( 因为其内部 实例变量的 值不可变 )
         Decimal d = new Decimal(100L);
         System.out.println(d.getValue());
         System.out.println(System.identityHashCode(d));
 ?
         System.out.println("=============");
 ?
 ?
         d = new Decimal(200L);
         System.out.println(System.identityHashCode(d));
 ?
 ?
         d = Decimal.valueOf(300L);
         System.out.println(System.identityHashCode(d));
 ?
    }
 ?
 }
 ?

 

  • 被 final 修饰的 类变量 在初始化之后不能 再次赋值 必须 显式赋值完成初始化

  • 被 final 修饰的 类变量 被称作 【常量】

2、获得某种基本数据类型 数值 对应的 包装类类型的实例

在 Java 9 之前通过 new 来获取 对应的包装类

在 Java 9 之后 通过 valueOf () 工厂方法来获取包装类

 package wrapper;
 ?
 /**
  * 获得某种基本数据类型 数值 对应的 包装类类型的实例
  * 在 Java 9 之前 使用包装类 的 构造方法创建实例
  * 在 Java 9 开始使用 valueOf 等方法获取实例
  *
  *
  * */
 ?
 public class WrapperTest {
 ?
     public static void main(String[] args) {
 ?
         // Java 9 之前 使用构造方法创建 相对应的实例
         byte b = 100;
         Byte first = new Byte(b); // 但是从 Java 9 之后就不赞成使用
 ?
         // Java 9 之前 使用构造方法创建 相对应的实例
         short s = 100;
         Short second = new Short(s); // 但是从 Java 9 之后就不赞成使用
 ?
 ?
         // 从 Java 9 开始 建议使用 工厂方法来创建 包装类的实例
         Integer third = Integer.valueOf(999); // 将 int 类型的数字 封装到 一个 Integer 实例中
         System.out.println(third);
 ?
         Long fourth = Long.valueOf(999L);
         System.out.println(fourth);  // fourth.toString()
 ?
 ?
         System.out.println("===============");
         System.out.println(fourth.getClass()); // 获取运行时 类型
         System.out.println(fourth.hashCode()); // 获得哈希码值
         System.out.println(fourth.toString()); // 获取字符串形式表示形式
 ?
 ?
         // 即使变量 fourth 指向的对象对应的类 重写的 hashCode 方法 所返回的值
 ?
 ?
 ?
    }
 ?
 ?
 }
 ?

 

3、八种基本类型对应的包装类都有一个将相对应的基本类型数据封装成该类的对象的 valueOf 方法中

 

 package wrapper;
 ?
 /** 八中基本类型对应的包装类都有一个将相对应的基本类型数据封装成该类的对象的 valueOf 方法中
  *
  * */
 ?
 public class WrapperTest2 {
     public static void main(String[] args) {
         // valueOf 接收一个与之对应的基本数据类型的数值做参数,返回的是一个 Byte 类型的对象
         Byte b = Byte.valueOf((byte) 100);
         System.out.println(b + "," + b.getClass());
 ?
         Short s = Short.valueOf((short) 100);
         System.out.println(s + "," + s.getClass());
 ?
         Integer i = Integer.valueOf(1000);
         System.out.println(s + "," + s.getClass());
 ?
         Long l = Long.valueOf(10000L);
         System.out.println(l + "," + l.getClass());
 ?
         Float f = Float.valueOf(1455.252f);
         System.out.println(f + "," + f.getClass());
 ?
         Double d = Double.valueOf(1455.252);
         System.out.println(d + "," + d.getClass());
 ?
         Boolean z = Boolean.valueOf(true);
         System.out.println(z + "," + z.getClass());
 ?
         Character c = Character.valueOf(‘a‘);
         System.out.println(c + "," + c.getClass());
 ?
 ?
 ?
    }
 }
 ?

4、八种基本数据类型对应的包装类中 除了 Character 类之外 都有一个将 字符串解析为 相对应的基本类型数值的方法

1、基本数据类型的数值 被包装 到一个相应的包装类类型的实例中

在 Java 9 之前 使用包装类 的 构造方法创建实例

在 Java 9 开始使用 valueOf 等方法获取实例

2、将 用字符串形式表示的值 解析为 基本类型的数值后

再将 基本类型的数据 封装到 一个 相应的包装类类型的实例中

注意事项 Character类中没有 valueOf(String) 方法

3、将 字符串形式 表示的值解析为 基本数据类型的值

4、对于整数类型来说,其相应的包装类中可以将 字符串形式 表示的值

按照指定的 radix 解析为 相应的进制数 最大 36 进制

5、通常在 Java 语言中 radix 范围 [2,36]

Character.MIN_RADIX , Character.MAX_RADIX

八种基本数据类型对应的包装类中 除了 Character 类之外 都有一个将 字符串解析为 相对应的基本类型数值的方法

 

 package wrapper;
 ?
 /**
  * 1、基本数据类型的数值 被包装 到一个相应的包装类类型的实例中
  * 在 Java 9 之前 使用包装类 的 构造方法创建实例
  * 在 Java 9 开始使用 valueOf 等方法获取实例
  *
  * 2、将 用字符串形式表示的值 解析为 基本类型的数值后
  * 再将 基本类型的数据 封装到 一个 相应的包装类类型的实例中
  * 注意事项 Character类中没有 valueOf(String) 方法
  * 3、将 字符串形式 表示的值解析为 基本数据类型的值
  *
  * 4、对于整数类型来说,其相应的包装类中可以将 字符串形式 表示的值
  * 按照指定的 radix 解析为 相应的进制数 最大 36 进制
  * 5、通常在 Java 语言中 radix 范围 [2,36]
  * Character.MIN_RADIX , Character.MAX_RADIX
  *
  * 八种基本数据类型对应的包装类中 除了 Character 类之外 都有一个将 字符串解析为 相对应的基本类型数值的方法
  *
  *
  * */
 public class WrapperTest4 {
     public static void main(String[] args) {
         final String x = "101";
 ?
         // radix 进制 最大36进制
         // Byte.parseByte("129"); // NumberFormatException
         byte b = Byte.parseByte(x); // String ===> byte
         System.out.println(b);
 ?
         byte b2 = Byte.parseByte(x,2); // String ===> byte
         System.out.println(b2);
 ?
         short s = Short.parseShort(x); // String ===> byte
         System.out.println(s);
 ?
         short s2 = Short.parseShort(x,2); // String ===> byte
         System.out.println(s2);
 ?
         int i = Integer.parseInt(x); // String ===> byte
         System.out.println(i);
 ?
         int i2 = Integer.parseInt(x,36); // String ===> byte
         System.out.println(i2);
 ?
         long l = Long.parseLong(x); // String ===> byte
         System.out.println(l);
 ?
         long l2 = Long.parseLong(x,36); // String ===> byte
         System.out.println(l2);
 ?
         System.out.println("~~~~~~~~~~~~~~~");
 ?
         float f = Float.parseFloat("3.14F");
         System.out.println(f);
 ?
         float f2 = Float.parseFloat("3.14");
         System.out.println(f2);
 ?
         double d = Float.parseFloat("3.14D");
         System.out.println(d);
 ?
         double d2 = Float.parseFloat("3.14");
         System.out.println(d2);
 ?
         boolean z = Boolean.parseBoolean("tRue");
         System.out.println(z);
 ?
         // 只要不是单词 true 都返回 false
         boolean z1 = Boolean.parseBoolean("True "); // 多了空格
         System.out.println(z1);
 ?
         // Character 类 中没有 解析为 字符的方法
 ?
    }
 ?
 }
 ?

 

5、将基本数据类型的数值 转换为 字符形式 表示

 

 package wrapper;
 ?
 ?
 /** 1、将基本数据类型的数值 转换为 字符形式 表示
  *
  * */
 ?
 public class WrapperTest5 {
     public static void main(String[] args) {
 ?
         final int x = 9527;
 ?
         String s = x + "";
         System.out.println(s + "," + s.getClass().getName());
 ?
         String ss = Integer.toString(x); // 返回整数的 十进制 字符串形式
         System.out.println(ss + "," + ss.getClass().getName());
 ?
         String binary = Integer.toString(x,2); // 返回整数的 二进制 字符串形式
         System.out.println(binary + "," + binary.getClass().getName());
 ?
         String b = Integer.toBinaryString(x);
         System.out.println(b);
    }
 ?
 }
 ?

 

6、将 基本数据类型的数值 封装到 其相应的包装类类型的实例中后 可以将这个数值当做 一个对象来对待

 

 package wrapper;
 /**
  * 1、Byte、Short、Integer、Long、Float等 都继承了 Number 类
  * 2、将 基本数据类型的数值 封装到 其相应的包装类类型的实例中后 可以将这个数值当做 一个对象来对待
  *
  * */
 ?
 public class WrapperTest6 {
     public static void main(String[] args) {
         Double d = null;
 ?
         d = Double.valueOf(664.1544);
         System.out.println(d); // toString
 ?
         byte b = d.byteValue();
         System.out.println(b);
 ?
         int i = d.intValue();
         System.out.println(d);
 ?
         float f = d.floatValue();
         System.out.println(f);
 ?
         boolean x = d.isNaN();
         System.out.println(x);
 ?
 ?
         System.out.println("==============");
 ?
         Character character = Character.valueOf(‘A‘);
 ?
 ?
    }
 }
 ?

 

7、自动装箱 ( Auto-Boxing )

概念:所谓自动装箱 就是 将基本类型的数值 自动包装 到一个 包装类类型的实例中

自动装箱 和 自动拆箱 以个人的理解只发生在 基本类型的包装类上

 

装箱: int x = 100;

Integer o = x ; // 自动装箱 虚拟机自动完成的

相当于 Integer o = Integer.valueOf( x );

 

 package wrapper;
 /**
  * 1、JDK 1.5 老特性 自动装箱 ( AutoBoxing )
  *     所谓自动装箱 就是 将基本类型的数值 自动包装 到一个 包装类类型的实例中
  *
  * */
 ?
 public class AutoBoxing {
     public static void main(String[] args) {
 ?
         int x = 100; // 基本类型
 ?
         Integer o = x; // 将 基本类型 变量中 存储的值 赋值给 包装类类型的 引用变量时,就会发生自动包装
         System.out.println("o:" + o); // 引用类型 的 变量中存储的值 是 堆内存中某个对象的地址
 ?
         System.out.println(System.identityHashCode(o));
         System.out.println(Integer.toHexString(System.identityHashCode(o)));
 ?
 ?
         Integer n = Integer.valueOf(x); // 手动装箱
         System.out.println("n:" + n);
 ?
         Object object = x;
         System.out.println("Object:" + object);
         System.out.println("运行时类型:" + object.getClass());
 ?
         Object[] array = new Object[5];
         for (int i = 0; i < array.length; i++) {
             System.out.println(array[i]);
             System.out.println(i<array.length-1 ? "," : " ");
        }
         array[0] = 100; //自动装箱
         array[1] = 100;
         array[2] = 100;
         array[3] = 100;
         array[4] = 100;
         for (int i = 0; i < array.length; i++) {
             System.out.println(array[i]);
             System.out.println(i<array.length-1 ? "," : " ");
        }
    }
 }
 ?

 

8、自动拆箱 (Auto-Unboxing)

概念:所谓自动拆箱 就是 将 包装类类型的实例中的 基本类型的值 取出来

  • 用一个包装类的引用变量 参与 运算时 会发生自动拆箱

  • 仍然以基本数据类型的方式 运算

 package wrapper;
 ?
 /**
  * 1、JDK1.5老特性 自动拆箱(AutoUnboxing)
  * 2、所谓自动拆箱 就是 将 包装类类型的实例中的 基本类型的值 取出来
  * 仍然以基本数据类型的方式 运算
  *
  * 3、用一个包装类的引用变量 参与 运算时 会发生自动拆箱
  * */
 ?
 public class AutoUnboxing {
 ?
     public static void main(String[] args) {
         Integer x = Integer.valueOf(252);
 ?
         // 当将一个包装类类型的引用变量的值 "赋值" 给 一个基本数据的变量时 会发生自动拆箱
         int i = x; // AutoUnboxing
         System.out.println(i);
 ?
         int n = x.intValue(); // JDK 1.5 之前需要手动拆箱
         System.out.println(n);
 ?
         Long l = Long.valueOf(10000L);
         long z = l; // l.valueOf()
 ?
 ?
         Double d = Double.valueOf(3.14);
 ?
         double u = d + 1; // 自动拆箱
         System.out.println(u);
 ?
         Integer y = Integer.valueOf(520);
         System.out.println(y);
         System.out.println(Integer.toHexString(System.identityHashCode(y)));
         y++;
         System.out.println(y); // 521
         System.out.println(Integer.toHexString(System.identityHashCode(y)));
 ?
    }
 ?
 }
 ?

 

9、包装类中的缓存数组

以 Integer 类为例,存在一个 缓存数组 里面包含了 [-128,127] 中的基本数据类型 对应的 Integer 实例

如果不在这个范围的基本数据类型就需要重新的 new 一个新的 Integer 实例

 package wrapper;
 ?
 /**
  * 1、所谓的自动装箱 实际上就是由编译器将 相对应的代码 替换为 Xxx.valueOf(xxx value)
  * Integer.valueOf(int value) 方法会 判断对应数值是否在 [-128,127]之间
  * 如果是直接 从缓存数组中 直接取 不是则 new 一个 新的 实例
  * 2、在 Integer 类中 有一个 缓存数组 默认缓存了 [-128,127] 的数字对应的 Integer 实例
  *
  * */
 ?
 public class IntegerCacheTest {
     public static void main(String[] args) {
         int x = 100; // 基本类型
         Integer a = 100; // 引用类型
         Integer b = 100; // 引用类型
         System.out.println(System.identityHashCode(x));
         // x 和 a b 的地址一样
         // a 和 b 的地址是一样的
         System.out.println(System.identityHashCode(a));
         System.out.println(System.identityHashCode(b));
         System.out.println(a == b); // true 但凡是 == 比较两个变量 一定是比较变量中存储的值
         System.out.println(a == x); // true 自动拆箱 手动 拆箱后的代码 a.intValue == x
 ?
         // Object o = 100; // 自动装箱
         // System.out.println(o == x); // 错误
 ?
         Integer e = 1000;
         Integer f = 1000;
         System.out.println(e == f); // false ? 为什么
         System.out.println(System.identityHashCode(e));
         System.out.println(System.identityHashCode(f));
 ?
         System.out.println(e.equals(f)); // 比较 两个 Integer 包装类的基本数值比较 Integer 重写了 equals 方法
 ?
 ?
    }
 }
 ?

 

以上是关于包装类自动装拆箱缓存数组的主要内容,如果未能解决你的问题,请参考以下文章

java基础 深入解析常量池与装拆箱机制

java基础 深入解析常量池与装拆箱机制

Java基础 - 基本数据类型及包装类

24-从零玩转JavaWeb-包装类自动装箱自动拆箱

Java支持的数据类型有哪些?什么时候自动装拆箱?

JAVA学习笔记-自动装箱和自动拆箱(包装类)