Java入门系列之包装类(四)

前言

上一节我们讲解了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中引入自动装箱和拆箱之后,因版本的问题使用“==”来比较包装器对象可能会出现意想不到的结果。

原文地址:https://www.cnblogs.com/CreateMyself/p/11437026.html

时间: 2024-10-07 17:30:49

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

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

前言 我们知道在Java 8中对于HashMap引入了红黑树从而提高操作性能,由于在上一节我们已经通过图解方式分析了红黑树原理,所以在接下来我们将更多精力投入到解析原理而不是算法本身,HashMap在Java中是使用比较频繁的键值对数据类型,所以我们非常有必要详细去分析背后的具体实现原理,无论是C#还是Java原理解析,从不打算一行行代码解释,我认为最重要的是设计思路,重要的地方可能会多啰嗦两句. HashMap原理分析 我们由浅入深,循序渐进,首先了解下在HashMap中定义的几个属性,稍后会

Java入门系列:处理Json格式数据

本节主要讲解: 1)json格式数据处理方法 2)第三方工具包的使用方法 3)java集合数据类型 [项目任务] 编写一个程序,显示未来的天气信息. [知识点解析] 为了方便后面代码的分析,先需要掌握几个相关的知识. 1.什么是json格式数据 从结构上看,我们所见到的所有的数据(data)最终都可以分解成三种类型: 第一种类型是标量(scalar),也就是一个单独的字符串(string)或数字(numbers),比如"北京"这个单独的词. 第二种类型是序列(sequence),也就是

Java学习系列(二十四)Java正则表达式详解

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45501777 前言 正则表达式可以说是用来处理字符串的一把利器,它是一个专门匹配n个字符串的字符串模板,本质是查找和替换.在实例演示之前先了解一下Pattern.Matcher这两个工具类,Pattern:编译好的带匹配的模板(如:Pattern.compile("[a-z]{2}");/ / 取2个小写字母):Matcher:匹配目标字符串后产生的结果(如:pattern.m

Java入门系列-08-选择结构

这篇文章为你搞懂2个问题 if-else选择结构的使用? switch 的使用? 前面我们学习的代码都是直上直下的执行,还不会"拐弯",这篇文章带大家来看一下会"拐弯"的代码--选择结构,顾名思义就有选择性的执行代码. if-else 选择结构 简单if结构 只有一种执行情况,表达式结果为true时执行结构内代码片段,为false时不执行 语法: if(表达式){ 代码片段 } 敲一敲: import java.util.Scanner; public class

Java NIO系列教程(四) Scatter/Gather

原文地址:http://ifeve.com/java-nio-scattergather/ Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作. 分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中.因此,Channel将从Channel中读取的数据“分散(scatter)”到多个Buffer中. 聚集(gather)写

Java入门系列:实例讲解ArrayList用法

本文通过实例讲解Java中如何使用ArrayList类. Java.util.ArrayList类是一个动态数组类型,也就是说,ArrayList对象既有数组的特征,也有链表的特征.可以随时从链表中添加或删除一个元素.ArrayList实现了List接口. 大家知道,数组是静态的,数组被初始化之后,数组长度就不能再改变了.ArrayList是可以动态改变大小的.那么,什么时候使用Array(数组),什么时候使用ArrayList?答案是:当我们不知道到底有多少个数据元素的时候,就可使用Array

Java入门 第二季第四章 多态

这是我学习慕课网Java课程的笔记,原视频链接为:http://www.imooc.com/learn/124 4-1 Java中的多态 定义:对象的多种形态 1. 引用多态 父类的引用可以指向本类的对象:父类的引用也可以指向子类的对象 继承是多态的实现基础  2. 方法多态 创建本类对象时,调用的方法为本类方法 创建子类对象时,调用的方法为子类重写的方法或者继承的方法 PS:不能调用子类独有的方法 4-2 多态中的引用类型转换 1. 向上类型转换(隐式/自动类型转换),是小类型到大类型的转换.

Java入门系列(十)Java IO

总体而言,java的读写操作又分为两种:字符流和字节流. 什么是流? 流是一个抽象的概念.当Java程序需要从数据源读取数据时,会开启一个到数据源的流.数据源可以是文件,内存或者网络等.同样,当程序需要输出数据到目的地时也一样会开启一个流,数据目的地也可以是文件.内存或者网络等.流的创建是为了更方便地处理数据的输入输出. 那么字节流和字符流又有什么区别呢? 1.字节流也称为原始数据,需要用户读入后进行相应的编码转换.而字符流的实现是基于自动转换的,读取数据时会把数据按照JVM的默认编码自动转换成

【Java入门系列】垃圾回收

垃圾回收 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收.除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此. 垃圾回收其实做了两件事:1.发现无用的对象:2.回收无用对象占用的内存空间. 垃圾回收算法 1.应用计数法 对象中添加一个引用计数器,每当一个地方引用这个对象时,计数器值+1:当引用失效时,计数器值-1.任何时刻计数值为0的对象就是不可能再被使用的.这种算法使用场景很多,但是,Java中却没有使用这种算法,因为这种算法很难解决对象之间相互引