java篇 常用工具类 0x05:基本类型的自动装箱拆箱

2024-09-01 02:20

本文主要是介绍java篇 常用工具类 0x05:基本类型的自动装箱拆箱,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 数字基本类型的封装类和常用方法
    • 字符基本类型的封装类和常用方法
    • 布尔基本类型的封装类和常用方法

java 从第一个版本开始,就为每种基本类型提供了封装的类,以便可以将其当作类而非基本数据类型使用。

比如 List、Map 这些类,都是操作 Object,无法操作基本数据类型。你无法用 int 作为 Map 的 key 或 value,所以 java 允许让 int 封装成其封装类 Integer 后来作为 Map 的 key 或 value。

java 提供了自动为每种基本数据类型和其对应的封装类之间的自动转换功能。

  • 自动封箱(auto boxing):从基本类型到封装类;
  • 自动拆箱(auto unboxing):从封装类到基本类型。

java 是通过创建实例(如 Integer.valueOf(int类型数据) 来对 int 进行封箱,或直接 new Integer(int类型数据))或返回缓存住的实例来实现自动封箱的,通过调用相应的转换方法实现自动拆箱的(如 int 是通过 Integer 调用 .intValue() 来拆箱获得)。

  • 所谓的“返回缓存实例”
    java 创建一个实例是需要一系列复杂操作的:调用构造方法、分配一块内存等。
    而拆箱和封箱又是频繁发生的事情,所以 java 会缓存住一些实例,比如说 Integer,java 会缓存住256个Integer实例(-128~127,通过 Integer 的内部类 IntegerCache 类来实现,在类加载时创建了 256 个Integer实例),进行自动封箱时,java 会先去找找有没有这个缓存的实例,没有的话再去创建。

// java 会对 -128~127 进行缓存,即类加载时,缓存 256 个 Integer 对象  Integer i1 = 1;  
Integer j1 = 1;  
System.out.println(i1==j1); // true  
// == 判断的是是否为同一个对象,因此 i1 和 j1 是同一个对象  
// 可见直接将数字 1 封箱,其实并没有创建新的对象,而是直接用了缓存的 Integer 对象  Integer j2 = new Integer(1);  
System.out.println(i1==j2); // false  
// 因此,用 new Integer(1) 的方式是真的创建了一个新的 Integer 对象,因此和缓存中的 Integer 对象不是同一个对象  // 检验缓存上界  
Integer i127 = 127;  
Integer i128 = 128;  
Integer j127 = 127;  
Integer j128 = 128;  
System.out.println(i127==j127); // true  
System.out.println(i128==j128); // false  
// 说明的确上限只换存到了 127  
// 检验缓存下界  
Integer i_128 = -128;  
Integer i_129 = -129;  
Integer j_128 = -128;  
Integer j_129 = -129;  
System.out.println(i_128==j_128); // true  
System.out.println(i_129==j_129); // false  
// 说明的确下限只缓存到了 -128

[!warning] 封装类之间是无法相互转换的
基本类型 int 是可以自动转换成 double 的,甚至 double 可以强制转换成 int(只是会造成精度丢失:直接截取整数部分,而非对小数四舍五入成整数)。
但 Integer 与 Double 互相无法自动转换或强制类型转换。

另外封装类型也是不可变的。如 Integer 是没有 .set()方法的。这些和 String 是一样的,对象一旦创建出来就是不能变的(当然,你可以让同一个引用指向另一个对象,但是对象本身是不可改变的)。所以可以放心地将封装类型作为 Map 的 key。

数字基本类型的封装类和常用方法

和数字相关的基本数据类型为:byte、short、int、long、float、double;

和数字相关的基本数据类型对应的封装类依次为:Byte、Short、Integer、Long、Float、Double。

// Byte
public final class Byte extends Number implements Comparable<Byte> {...}// Short
public final class Short extends Number implements Comparable<Short> {...}// Integer
public final class Integer extends Number implements Comparable<Integer> {...}// Long
public final class Long extends Number implements Comparable<Long> {...}// Float
public final class Float extends Number implements Comparable<Float> {...}// Double
public final class Double extends Number implements Comparable<Double>{...}

可以看到,数字基本类型的封装类,都是 Number 类的子类。

下面以 int 与 Integer 为例,介绍数字基本类型的自动拆箱、自动封箱,以及常用方法。

import java.util.HashMap;  
import java.util.Map;  public class WrapperClassesForNumber {  public static void main(String[] args) {  int a = 100;  // new Integer() 可以接收 int 或 String 来创建一个 Integer 实例  Integer i1 = new Integer(a);  Integer i2 = new Integer("123");  // Integer i3 = "345"; // 报错  // Integer.valueOf() 接收一个 int,返回一个 Integer,但是这个 Integer 能直接赋值给 int 引用b,这是因为这个赋值过程 java 会自动拆箱。  int b = Integer.valueOf(a);  // Integer.parseInt() 则是接收一个 String,返回的本身就是一个 int,然后赋值给一个 int 引用c,所以这里没有自动拆箱。  int c = Integer.parseInt("321");  System.out.println("----------自动封箱和拆箱----------");  // java 提供了自动为每种基本数据类型和其封装类之间的转换功能  // 拆箱就是把封装类的值取出来,赋给其对应的基本类型。  // 封箱则是把基本类型封装成其对应的封装类的一个实例。  // 自动,则是指 java 会在有这种转换需求的时候,自动帮你完成这种转换(封箱或拆箱)  Integer ab = 200; // 自动封箱  int cd = ab; // 自动拆箱  // 自动封箱为 Integer,作为 Map 中的 key。  Map<Integer, String> int2Str = new HashMap<>();  // 你不能写成 Map<int,String> int2Str,声明类型是需要用封装类的,但用的时候,java 会帮你自动封箱,把传入的 int 封装成 Integer// .put() 按定义是要传入 Integer 与 String 的  int2Str.put(1, "一");  int2Str.put(2, "二");  int2Str.put(3, "三");  // .get() 按定义是要传入 Object 的,这里同样是将 int 自动封装成了 Integer,然后赋给 Object。  System.out.println(int2Str.get(1)); // 一  // 自动拆箱为 int,并给 key 赋值  for (int key : int2Str.keySet()) {  // .keySet() 迭代出来的元素是 Integer,你让它赋值给 int 引用(key),java 就会对其自动拆箱成 int。  System.out.println(key);  }  /*  1  2  3  */  // Integer 封装类的常用方法  System.out.println("----------常用方法----------");  // Integer.toBinarySring() 接收 int,返回这个整数的二进制,并将这个二进制数用 String 方式返回  System.out.println(Integer.toBinaryString(1024)); // 10000000000  System.out.println(Integer.toBinaryString(-1024)); // 11111111111111111111110000000000  // Integer.toOctalString() 接收 int,返回这个整数的八进制,并将这个八进制数用 String 方式返回  System.out.println(Integer.toOctalString(1024)); // 2000  System.out.println(Integer.toOctalString(-1024)); // 37777776000  // Integer.toHexString() 接收 int,返回这个整数的十六进制,并将这个十六进制数用 String 方式返回  System.out.println(Integer.toHexString(1024)); // 400  System.out.println(Integer.toHexString(-1024)); // fffffc00  System.out.println("----------Number类----------");  // 所有和数字相关的封装类,都继承自 Number 抽象类  Number num = 9; // 这里其实就是用父类 Number 引用指向子类 Integer 实例,但实际传入的是 int,因此这里 java 也是做了自动封箱,把 int 封装成 Integer。  num = new Integer(12345);  Number numD = 9.99; // 同样,这里是父类 Number 引用指向子类 Double 实例,而传入的是 double,所以 java 也是做了自动封箱,把 double 封装成 Double。  numD = new Double(12.345);  // 使用 Nubmer 类可以方便地使用数字类型的转换  // 当然所有的类都继承了 Nubmer 的这些转换方法  System.out.println("使用Number将Double转为byte:" + numD.byteValue()); // 使用Number将Double转为byte:12  System.out.println("使用Number将Double转为short:" + numD.shortValue()); // 使用Number将Double转为short:12  System.out.println("使用Number将Double转为int:" + numD.intValue()); // 使用Number将Double转为int:12  System.out.println("使用Number将Double转为long:" + numD.longValue()); // 使用Number将Double转为long:12  System.out.println("使用Number将Double转为float:" + numD.floatValue()); // 使用Number将Double转为float:12.345  System.out.println("使用Number将Double转为double:" + numD.doubleValue()); // 使用Number将Double转为double:12.345  /*  其实所谓的自动拆箱,就是 java 自动调用了该基本数据类型的封装类的 .xxxValue() 方法,返回了对应的基本数据类型。  比如 Integer 自动拆箱成 int,就是调用了 Integer 的实例方法 .intValue(),返回了 int 类型的值。  */  // 自动拆箱可能会引起NPE异常(NullPointerException)  int2Str.put(null, "无");  System.out.println(int2Str.get(null)); // 无  // 上面这两句并没有涉及自动拆箱或封箱,因为没有发生基本类型和引用类型的转换。  // 自动拆箱为 int,并给 key 赋值,但是有一个 key 为 null,null 是无法转成一个 int 的  // (注意:null 不是 0,0是实实在在的一个数,0 的 int 是可以和 Integer 自动转换的,但 null 其实是“空”,是引用类型的缺省值,但并不能转成 int)。  // 其实自动拆箱,后面是 java 帮我们调用了对应的方法,在这里就是 intValue() 这个方法  // 所以当引用为 null 的时候自动拆箱,相当于是调用 null 的方法,所以这时候会发生 NPE// 对于其他封装类型的自动拆箱,也是一样的。  // for (int key : int2Str.keySet()) {  // // 这里因为 .keySet() 迭代出来的元素中除了有 Integer 还有一个 null,  // // Integer 可以自动拆箱成 int,但 null 转成 int 时,同样自动调用 .intValue() 时,因为无法对 null 调用实例方法,就会报错 NPE。  //     System.out.println(key);  // }  // /*  // 运行报错:NullPointerException  // */  /*  其实这里引出了一种用法:就是,数字基本类型是没有 null 的说法的,  声明一个数字基本类型的成员变量,默认就赋予一个缺省值 0,你无法区分这个 0 是初始值还是你后面赋的值,你无法让它是空的(来表明你从来没有对它赋值)。  这时候,你就可以考虑不使用数字的基本类型,而使用其对应的封装类。其缺省值就是 null,可以用来表明你从没有对它赋值。  所以在有数据交换的时候,建议使用封装类。这样就允许你把它设置成 null,来表明你从没有对它赋过值。  */  }  }

字符基本类型的封装类和常用方法

字符基本类型 char 对应的封装类是 Character。

Character 中有很多叫 isXXX() 的静态方法,比较实用。

而至于字符基本类型和其封装类的自动封箱和拆箱,就不赘述了,和数字类型的拆箱封箱是一样的,都是 java 在我们需要的时候会自动完成转换。

public class WrapperClassesForChar {  public static void main(String[] args) {  // char 对应的封装类是 Character,里面有很多 isXXX 方法比较实用,  // 比如判断字符是否为数字 isDigit() 可以接收 char 或 int,返回 boolean。  System.out.println(Character.isDigit('A')); // false  System.out.println(Character.isDigit('啊')); // false  System.out.println(Character.isDigit('9')); // true  System.out.println(Character.isDigit('0')); // true  // System.out.println(Character.isDigit('123')); // 报错,因为 char 是单字符的  // 其实isDigit()一般常用的是 char 作为形参,也比较直观判断一个字符是否是数字  // isDigit() 接收的是 int 的话,含义有点绕,是判断这个 int 对应的 unicode 对应的编码是否用来表示数字(因为可能是用来表示一个字母、符号而非数字)  System.out.println(Character.isDigit(0x06f8)); // true (因为'u06F0' ~ 'u06F9', 扩展阿拉伯语,印度语数字)  System.out.println(Integer.toString(0x06f8)); // 1784  System.out.println(Character.isDigit(1784)); // true  System.out.println(Character.isDigit(9)); // false  System.out.println(Character.isDigit(37)); // false  System.out.println(0x37); // 55  System.out.println(Character.isDigit(55)); // true  System.out.println(Character.isDigit(0x37)); // true (因为'u0030' ~ 'u0039', ISO-LATIN-1 数字('0' through '9'))  /*  这是因为  'u0030' ~ 'u0039', ISO-LATIN-1 数字('0' through '9')  'u0660' ~'u0669', 阿拉伯 - 印度文数字  'u06F0' ~ 'u06F9', 扩展阿拉伯语,印度语数字  'u0966' ~ 'u096F', Devanagari 数字  'uFF10' ~ 'uFF19', 全角数字  当然也不只有这些范围是数字,还有别的范围也有数字  */  // isXXX 还有诸如判断字符大小写的 isLowerCase() 与 isUpperCase() ,  // 也都是可以接收 char 或 int,但常用的都是接收 char,  // 接收 int 的含义判断也和 isDigit 类似,比较绕,是判断对应unicode表示的字符是否是大写/小写字母,这里就不深究了  System.out.println(Character.isLowerCase('A')); // false  System.out.println(Character.isLowerCase('a')); // true  System.out.println(Character.isUpperCase('A')); // true  System.out.println(Character.isUpperCase('a')); // false // 非字母的字符自然没有所谓的大小写,所以通通都是 false。System.out.println(Character.isLowerCase('3')); // falseSystem.out.println(Character.isUpperCase('3')); // falseSystem.out.println(Character.isUpperCase('0')); // false  System.out.println(Character.isUpperCase('一')); // false}  
}

布尔基本类型的封装类和常用方法

布尔基本类型 boolean 的封装类是 Boolean。

由于 boolean 比较特殊,只有两个值 true 和 false,所以 Boolean 特意定义了两个静态常量:
Boolean.TRUEBoolean.FALSE(注意都是字母大写的,不仅仅是首字母)。

public class WrapperClassesForBoolean {  public static void main(String[] args) {  System.out.println("----------静态变量----------");  System.out.println(Boolean.TRUE); // true  System.out.println(Boolean.FALSE); // false  // 其实这里也是自动拆箱了,因为这两个静态变量的类型是 Boolean,而非其对应的基本类型 boolean。  System.out.println(Boolean.TRUE == true); // true  System.out.println(Boolean.FALSE == false); // true// 上面两句同样是自动拆箱了  System.out.println("----------valueOf----------");  // 只有不区分大小写的 true 才是 true,剩下的字符串都是 falseSystem.out.println(Boolean.valueOf("true")); // true  System.out.println(Boolean.valueOf("TruE")); // true  System.out.println(Boolean.valueOf("tRue")); // true  System.out.println(Boolean.valueOf(" true")); // false (因为多了一个空格)  System.out.println(Boolean.valueOf("false")); // false  System.out.println(Boolean.valueOf("abcd")); // false  }  
}

这篇关于java篇 常用工具类 0x05:基本类型的自动装箱拆箱的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1125669

相关文章

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

Spring MVC如何设置响应

《SpringMVC如何设置响应》本文介绍了如何在Spring框架中设置响应,并通过不同的注解返回静态页面、HTML片段和JSON数据,此外,还讲解了如何设置响应的状态码和Header... 目录1. 返回静态页面1.1 Spring 默认扫描路径1.2 @RestController2. 返回 html2

使用Python进行文件读写操作的基本方法

《使用Python进行文件读写操作的基本方法》今天的内容来介绍Python中进行文件读写操作的方法,这在学习Python时是必不可少的技术点,希望可以帮助到正在学习python的小伙伴,以下是Pyth... 目录一、文件读取:二、文件写入:三、文件追加:四、文件读写的二进制模式:五、使用 json 模块读写

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去

Java操作ElasticSearch的实例详解

《Java操作ElasticSearch的实例详解》Elasticsearch是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在Java应用中使用Elastics... 目录简介环境准备1. 安装 Elasticsearch2. 添加依赖连接 Elasticsearch1. 创