前言

上一节我们讲解了StringBuilder VS StringBuffer以及二者区别,本节我们来讲解包装类。

包装类

我们知道在Java中有8中基本数据类型,分为数值类型:byte、short、int、long、float、double。字符类型:char。布尔类型:bool,那么什么是包装类呢?包装类是8种基本数据类型的对象表示,而且8种包装类和字符串对象一样是不可变且final(不可通过继承或扩展破坏不可变性)的。我们通过查看int的包装类型Integer可知,如下:

如下为基本数据类型对应的包装类以及构造函数参数:

基本数据类型 包装类型 构造参数
byte Byte byte or String
short Short short or String
int Integer int or String
long Long long or String
float Float float, double or String
double Double double or String
char Character char
boolean Boolean boolean or String

比如当我们实例化Integer包装类时,既然是对int的包装,要是我们传一个带小数位的数字,毫无疑问也就抛出如下异常了:

public class Main {

    public static void main(String[] args) {
Integer a = new Integer("12.5");
}
}

开头我们就直接抛出了包装类的概念,但是不知道您是否有和我一样的疑惑,我们为什么要用包装类呢?比如Integer是对int的包装,我们直接使用int不就完事了吗,怎么还包装一层呢?这就需要我们了解包装类的作用是什么了?

1.包装类将基本数据类型转换为对象(当我们需要在给定方法中传递参数时需要对象)。

2.包java.util只处理对象的类,所以包装类在这个包中也有其用武之地。

3.数据结构仅存储对象和基本数据类型。

4.在多线程中,我们需要对象来支持线程同步。

或者说存在即合理,在Java中将包装类和基本数据类型区分开这是明智之举,当我们以适合面向对象的方式编程时,我们使用包装类,当处理起来更加简单时,我们使用基本数据类型,一切取决于我们。

自动装箱和拆箱

在Java 5中引入了自动装箱和拆箱,这允许基本数据类型和包装类相互之间能够轻松自如的实现转换。接下来我们通过基本数据类型和包装类转换实现装箱和拆箱,装箱则是自动将基本数据型转换为包装类,拆箱反之。

        char ch = 'a';
Character a = ch; ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(25);
System.out.println(arrayList.get(0));

如上第一个我们将基本数据类型转换为对象以及我们初始化集合且参数类型为包装类(对象),紧接着我们在此集合中添加基本数据类型为25的int,都自动实现了装箱。反过来,如下我们将实现拆箱:

        Character ch = 'a';
char a = ch;
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(24);
int num = arrayList.get(0);
System.out.println(num);

上述我们首先将包装类转换为基本数据类型,紧接着我们添加基本数据类型为24的int,这属于装箱,但是最后我们获取数据时赋值给为int的num,也就达到了将包装类到基本数据类型的转换,也就是拆箱。同时我们还需谨记:包装类可以为空,基本数据类型不能为空。也就是说要使其可空,我们必须使用包装类,这一点比不上C#语法高级,若基本数据类型可空,在C#中可如下定义:

int? a = null;
Console.WriteLine(a == null);

接下来我们来看如下一道题,请问:如下是自动装箱吗?如果不是体现了什么呢?

public class Main {

    public static void main(String[] args) {

        char c = 'a';

        doSomething(new Character(c));
} static void doSomething(Object obj) { } }

我们知道自动装箱是将基本数据类型转换为包装类,上述我们定义了一个doSomething方法,参数为Object类型,在程序入口点,我们调用该方法且传入的参数为包装类,所以上述并不是自动装箱,它所体现的是通过包装类实现多态。所以我们需谨记:自动装箱是将基本数据类型转换为包装类,而不是将一种数据类型转换为其他数据类型,这也许就是为什么自动装箱不能将String转换为包装类的原因。

数据类型转换

我们依然以基本数据类型int为例,在int对应的包装类Integer中有intValue方法实现拆箱,比如我们想要将double转换为int,利用包装类实现则是如下形式:

        double d = 135.d;
Double doubleWrapper = new Double(d);
int integerValue = doubleWrapper.intValue();
System.out.println(integerValue);

我们也可以使用包装类类型通过拆箱转换成其他基本数据类型,当我们需要将基本数据类型转换为对象并使用它们来获取其他基本数据类型时,将使用这种类型的转换。通过如上转换,我们需要编写一大片代码, 然而,我们可以通过如下简单的方式来实现相同的目的:

        double d = 135.d;
int integerValue = (int)d;
System.out.println(integerValue);

valueOf和parseInt使用详解

到目前我所知道的有以下两种方式将String对象转换为int或Integer,我们一起来看看。

Integer.parseInt

此种方式作为将String转换为int的首先方式,简单且灵活,我们看一个例子:

int i = Integer.parseInt("123");
System.out.println("i: " + i);

如果提供的String不是正确的数字,Integer.parseInt()方法将抛出NumberFormatException异常,相同的方式同样适用于其他数据类型(如float和Double)转换为Java中的String。 Java API提供静态方法,如Float.parseFloat()和Double.parseDouble(),以执行数据类型转换。

Integer.valueOf

在8种包装类中都有这个valueOf方法,这也是一种将String转换为int的方式,我们同样来看一个示例:

 int i = Integer.valueOf("000000081");
System.out.println("i: " + i);

它将忽略前导零并将字符串转换为int。如果提供的String不是正确的数字,同样也会抛出NumberFormatException异常。在Java 1.4之前没有自动装箱,但是在Java 1.5即(Java 5+)引入了自动装箱,所以推荐使用Integer.valueOf(int)而不是new Integer(int),因为Integer现在可以在-128到127之间缓存Integer对象,并且每次都可以将同一个完整的Integer(0)对象交给我们,而不是在全新的相同Integer对象上浪费对象构造。

下面我们来看两个例子来验证上述源码观点:

        Integer i1 = 260;
Integer i2 = 260;
if (i1 == i2) {
System.out.println("i1 and i2 is equal");
} else {
System.out.println("i1 and i2 is not equal ");
}

接下来我们再来看一个例子,如下:

        Integer i1 = 100;
Integer i2 = 100;
if (i1 == i2) {
System.out.println("i1 and i2 is equal");
} else {
System.out.println("i1 and i2 is not equal ");
}

我们看到“i1和i2相等”,因为-128到127之间的int值在大多数JVM要缓存的范围内,所以VM实际上对i1和i2使用相同的对象实例(因此也使用同一内存地址),所以打印出相等。Integer.valueOf方法还有重载,我们来看一个例子:

        Integer I = Integer.valueOf("100", 2);
System.out.println(I);
Integer i = Integer.valueOf("101", 4);
System.out.println(i);

第二个参数表示进制,例如上述两个通过2进制表示100,通过4进制表示101,计算方式如下:

2进制表示100:(1 * 2 ^ 2)+(0 * 2 ^ 1)+(0 * 2 ^ 0)= 4 + 0 + 0 = 4。

4进制表示101:(1 * 4 ^ 2)+(0 * 4 ^ 1)+(1 * 4 ^ 0)= 16 + 0 + 1 = 17。

总结

valueOf和parseInt方法都用于在Java中将String转换为Integer,但它们之间存在细微差别(在Java 1.5引入自动装箱后),我们通过查看valueOf()方法的源码得知,发现它在内部调用parseInt()方法将String转换为Integer,但是它还维护一个从-128到127的整数池,如果请求的整数在池中,它从池中返回对象,这也意味着使用valueOf()方法返回的两个整数对象可以通过相等运算符相同,这种对不可变对象的缓存,确实有助于减少垃圾并帮助垃圾收集器。 parseInt()和valueOf()方法之间的另一个区别是返回类型,valueOf()返回一个Integer对象,而parseInt()方法返回一个int基本数据类型。无论是使用parseInt还是valueOf将String转换为基本数据类型Int和包装类Integer,如果我们需要基本数据类型Int可以使用parseInt,由于不可变对象可以安全地缓存在池中并且得到重用,如此一来减少了垃圾收集器的负载,因此如果需要Integer对象,最好使用valueOf。

Java中的“==”或等于运算符是Java编程语言提供的二元运算符,用于比较基元和对象,在比较boolean,int,float等基本数据类型时,利用“==”工作正常,但在比较对象时,它会与Java中的equals方法产生混淆, “==”根据内存引用比较两个对象。 所以“==”运算符只有在两个对象引用比较时才返回true来表示完全相同的对象,否则“==”将返回false。在Java 5中引入自动装箱和拆箱之后,因版本的问题使用“==”来比较包装器对象可能会出现意想不到的结果。

Java入门系列之包装类(四)的更多相关文章

  1. Java NIO系列教程(四) Scatter 和 Gather

    Java NIO系列教程(四) Scatter 和 Gather Java NIO 开始支持 scatter/gather,scatter/gather 用于描述从 Channel(译者注:Chann ...

  2. Java 设计模式系列(十四)命令模式(Command)

    Java 设计模式系列(十四)命令模式(Command) 命令模式把一个请求或者操作封装到一个对象中.命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复 ...

  3. 数据挖掘入门系列教程(四)之基于scikit-lean实现决策树

    目录 数据挖掘入门系列教程(四)之基于scikit-lean决策树处理Iris 加载数据集 数据特征 训练 随机森林 调参工程师 结尾 数据挖掘入门系列教程(四)之基于scikit-lean决策树处理 ...

  4. Java入门系列-19-泛型集合

    集合 如何存储每天的新闻信息?每天的新闻总数是不固定的,太少浪费空间,太多空间不足. 如果并不知道程序运行时会需要多少对象,或者需要更复杂方式存储对象,可以使用Java集合框架. Java 集合框架提 ...

  5. Java入门系列 泛型

    前言 <Java编程思想>第四版足足用了75页来讲泛型——厚厚的一沓内容,很容易让人头大——但其实根本不用这么多,只需要一句话:我是一个泛型队列,狗可以站进来,猫也可以站进来,但最好不要既 ...

  6. Java入门系列-26-JDBC

    认识 JDBC JDBC (Java DataBase Connectivity) 是 Java 数据库连接技术的简称,用于连接常用数据库. Sun 公司提供了 JDBC API ,供程序员调用接口和 ...

  7. Java入门系列 Java 中的四种引用

    Why java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象. java对象的引用包括强引用,软引用,弱引用,虚引用 Java中提供这四种引用类型 ...

  8. Java入门系列(四)内部类

    为什么需要内部类? 真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题没有多继承.实际上,C++的多继承设计起来很复杂,而java通过内部类加 ...

  9. Java入门系列之集合HashMap源码分析(十四)

    前言 我们知道在Java 8中对于HashMap引入了红黑树从而提高操作性能,由于在上一节我们已经通过图解方式分析了红黑树原理,所以在接下来我们将更多精力投入到解析原理而不是算法本身,HashMap在 ...

随机推荐

  1. django----Sweetalert bulk_create批量插入数据 自定义分页器

    目录 一.Sweetalert使用AJAX操作 二.bulk_create 三.分页器 divmod 分页器组件 自定义分页器的使用 一.Sweetalert使用AJAX操作 ​ sweetalert ...

  2. 网络编程基础之socket套接字编程实现同一IP下的信息传输

    鲁照山 1.网络协议的5层模型,每层内容的整理 2.画图描述三次握手四次挥手,和C端S端的状态 3.写一个客户端,实现给服务端发送hello world 字符串, 写一个服务端,将客户端发送的数据变成 ...

  3. Vue.js 一问一答

    Vue.js 一问一答 记录一下在学习 Vue 过程中给自己问的一些问题,持续更新中... Vue.js 的核心是什么? 官网:Vue.js 的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进 ...

  4. 《Dotnet9》系列-FluentValidation在C# WPF中的应用

    时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...

  5. ReadWriteLock场景应用解析

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

  6. 百度大脑IOCR财会票据识别技术接入小程序,快速实现财会票据识别

    本文主要介绍iOCR财会票据识别的小程序功能实现. 想了解微信小程序的开发过程,请参看我之前的帖子:<UNIT接入小程序>https://ai.baidu.com/forum/topic/ ...

  7. Linux_crontab参数表示的意思

    *       *      *       *      * (下面的字体对应) 分     时    日    月    周 星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满 ...

  8. Java之数据库表字段有关键字报错java.sql.SQLSyntaxErrorException

    前两天在开发中遇到一个坑,本来我在快乐的做着增删改查,然后悲剧发生了,在查询数据库的过程中,报了java.sql.SQLSyntaxErrorException: 经过排查,是因为数据库表字段中存在关 ...

  9. IT兄弟连 HTML5教程 响应式布局实例

    在学习Media Queries模块前,先通过一个响应式布局实例来了解一下响应式布局和Media Queries模块的简单应用.在本例中,使用HTML5的结构元素定义了5个盒子.当浏览器窗口尺寸不同时 ...

  10. android上如何写配置文件

    android上如何写配置文件:使用SharedPreferences SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,比如Activity状态 ...