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

前言

上一节咱们讲解了StringBuilder VS StringBuffer以及两者区别,本节咱们来说解包装类。java

包装类

咱们知道在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只处理对象的类,因此包装类在这个包中也有其用武之地。app

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

4.在多线程中,咱们须要对象来支持线程同步。函数

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

自动装箱和拆箱

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

相关文章
相关标签/搜索