前言

上一节我们讲解了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. JavaScript原型 补充

    js原型 // 构造函数 = 类 function A(){} let a1 = new A(); // 添加原型 num => 类似于属性 A.prototype.num = 100; con ...

  2. JSP注册登录页教程

    转载请标明原文地址:http://www.cnblogs.com/zhangyukof/p/6785258.html  一.准备工作 已搭建好的SSH框架工程一个,如果没有,请参考我的上一篇文章< ...

  3. HttpRunner学习8--使用debugtalk.py辅助函数

    前言 在HttpRunner中,我们的测试用例都是写在 YAML/JSON 文件中,有时候我们想借助代码来实现某些较复杂的功能,但在 YAML/JSON 中是无法直接写代码来处理的,这个时候,我们可以 ...

  4. Spring Boot 部署浅析(jar or war)

    对于传统的 ssm 或者 ssh 项目的部署,一般会打包成war包,或者是一个编译好的文件夹,再放到 tomcat 的 webapps 目录下,如果是 war 包,会自动解压出来.而 Spring B ...

  5. [ASP.NET Core 3框架揭秘] 跨平台开发体验: Linux

    如果想体验Linux环境下开发.NET Core应用,我们有多种选择.一种就是在一台物理机上安装原生的Linux,我们可以根据自身的喜好选择某种Linux Distribution,目前来说像RHEL ...

  6. C#基础——break ,continue, return用法

  7. 渗透测试初学者的靶场实战 2--墨者学院SQL注入—报错盲注

    墨者SQL注入-MYSQL数据库实战环境 实践步骤 1. 决断注入点 输入单引号,提示错误信息: 输入and 1=1 返回页面正常: 输入 and 1=2 返回正常 输入-1,返回异常: 2. 带入s ...

  8. Android设置EditText不可编辑

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/224 禁用EditText 这个其实很简单,最简单的一种方 ...

  9. 一键删除数据库所有的外键约束-FOREIGN_KEYS

    DECLARE @ESQL VARCHAR(1000);DECLARE FCursor CURSOR --定义游标FOR (SELECT  'ALTER TABLE '+O.name+' DROP  ...

  10. LICEcap 动画屏幕录制软件

    下载地址    https://licecap.en.softonic.com/ LICEcap捕捉屏幕的区域并保存为gif动画或lcf格式 效果请看下面的链接 https://www.cnblogs ...