《Java核心技术》第10版读书笔记之Chap5(4)——基本数据类型的Wrapper类、自动拆箱与装箱及过程中的坑
来源:互联网 发布:大数据开发工程师简历 编辑:程序博客网 时间:2024/06/05 05:36
Java语言中虽然提供了byte、short、int、long、char、boolean、float、double这些基本数据类型,但由于他们并不是对象,因此有些操作会受到限制,比如不能将其存入容器中等等。为此Java在java.lang包中对于上述每一种基本类型都提供了一个对应的封装类(Wrapper),这些包装类中有一个不可变的对应基本类型的成员变量(也意味着一旦设定就没法更改了)并提供了若干方法。
仍然以Integer为例,看看Wrapper类型都提供了哪些功能:
1.字符串与基本数据类型的互转:XX.parseXX方法与XX.toString(XX)静态方法
需要注意的是,待转换的字符串必须符合对应类型的规定,否则在运行期会抛出解析错误的异常:
public static void main(String[] args) { int n1 = Integer.parseInt("666666"); int n2 = Integer.parseInt("-666666"); int n3 = Integer.parseInt(" 2333333"); System.out.println(n1); System.out.println(n2); }
在这段代码中,n1和n2能被正常解析出来,但在执行Integer.parseInt(” 2333333”)时,由于输入的字符串中包含空格,其不能解释为数字,所以发生异常:
Exception in thread "main" java.lang.NumberFormatException: For input string: " 2333333" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Integer.parseInt(Integer.java:569) at java.lang.Integer.parseInt(Integer.java:615) at CMain.main(CMain.java:11)
此外,Integer类还有一个重载的parseInt方法,输入的是字符串和进制数,字符串里的内容会被按照对应的进制数解析,如下列代码的运行结果就为16:
public static void main(String[] args) { int n1 = Integer.parseInt("1100", 2); System.out.println(n1); }
另外,将基本数据类型转换为字符串的方法之前的文章已经提到过了,直接用”” + 的方式即可,即用空串连接上一个基本数据类型即可。当然,也可以选择使用Integer.toString(int)方法,该方法为静态方法,会返回对应基本类型的字符串表示。
public static void main(String[] args) { String s1 = Integer.toString(23); String s2 = Integer.toString(23, 2); String s3 = "" + 233; System.out.println(s1); System.out.println(s2); System.out.println(s3); }//对应的结果分别是://23//10111//233
对于Integer类型,还有如下静态方法可供调用:
- 进制转换toBinaryString(int)方法
- toHexString(int)
- toOctalString(int)
2.构造方法
以int类型对应的Integer封装类为例,其源码中有如下片段:
public final class Integer extends Number implements Comparable<Integer> { //...... private final int value; public Integer(int value) { this.value = value; } //...... public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); } }
从中可以看出如下几点:
1. Wrapper类为final类型 2. 其中封装的基本类型也标明为final,意味着对象一旦创建,其表征的值就不能再被更改了 3. 可以用基本数据类型或字符串的方式构建一个对应的Wrapper对象
3.intValue方法:返回封装的基本数据类型。
public static void main(String[] args) { Integer n1 = new Integer("23333"); int n = n1.intValue(); System.out.println(n); }
4.MAX_VALUE与MIN_VALUE静态成员变量:最大值与最小值
这一点没有太多要说的,直接看Integer类的源码就知道了:
@Native public static final int MIN_VALUE = 0x80000000;@Native public static final int MAX_VALUE = 0x7fffffff;
5.自动装箱与自动拆箱——带着坑的语法糖
- 自动装箱:将基本数据类型赋值给Wrapper类,下面两条语句其实是等价的。
自动拆箱:将Wrapper类中的数据返回给基本数据类型
public static void main(String[] args) { Integer n1 = Integer.valueOf(333); Integer n2 = 333; }
正是因为有了javac编译器的自动装拆箱,才使得我们可能写出这样的代码:
ArrayList arrayInteger = new ArrayList<Integer>;arrayInteger.add(13);Integer n1 = 32;n1 = n1 + 233;
这里的13在加入arrayInteger中时会自动装箱,成为Integer类型。同理,n1也经过了自动装箱,成为了Integer类型。而当执行n1 + 233操作时,有需要对n1进行自动拆箱,加法运算结束后再通过自动装箱重新变回了Integer类型。
但是也需要注意,这种自动装拆箱机制是有弊端的:
每一次装箱都伴随着对象的创建,会耗费时空资源
对null的Wrapper类对象执行自动拆箱,会引发空引用异常。所以,尽量不要把Wrapper类对象引用设为null,宁可让其值为0。
Integer n3 = null;n3 = n3 + 233;/*上述代码执行时将引发如下异常:Exception in thread "main" java.lang.NullPointerExceptionat CMain.main(CMain.java:12)*/
Wrapper类型对象的值缓存机制
Integer类的valueOf静态成员方法源码如下:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
而其中的IntegerCache是Integer类的内部类。
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
可以看出,在该类中确实有缓存,且该缓存至少覆盖了[-128, 127]这个区间范围。所以,当自动装箱机制使用valueOf()方法时,在该区间范围内的数变会使用缓存里的实例,返回的也是这些缓存实例的引用。但是要注意,如果不使用自动装箱机制,而是直接new Integer(2)之类的方法创建对象,则不会有任何的缓存机制。
这点我印象十分深刻:曾经在做一个项目的时候,没有看清楚其Bean类中用的是Integer而非int,结果单测时用的数据是小于127的,没有发现问题。上线后,使用一段时间后用户反馈出现问题,检查后分析就是栽在了这个所谓的缓存机制上。
public static void main(String[] args) { Integer n1 = 127; Integer n2 = 127; System.out.println(n1 == n2); System.out.println(n1.equals(n2)); System.out.println("---------------------------------"); Integer n3 = 128; Integer n4 = 128; System.out.println(n3 == n4); System.out.println(n3.equals(n4)); System.out.println("---------------------------------"); Integer n5 = new Integer(127); Integer n6 = new Integer(127); System.out.println(n5 == n6); System.out.println(n5.equals(n6)); }
三组测试的结果分别是:
truetruefalsetruefalsetrue
所以,在Java中,对127以内的Byte、Short、Integer、Long对应的基本数据类型进行自动装箱,会从内建的缓存数组中引用同一个对象,而从128开始则不再使用这种缓存机制。另外这种缓存机制仅限于自动装箱的情况,对于显示new出的对象则无此机制。
- 《Java核心技术》第10版读书笔记之Chap5(4)——基本数据类型的Wrapper类、自动拆箱与装箱及过程中的坑
- 《Java核心技术》第10版读书笔记之Chap5(1)——类的继承
- 《Java核心技术》第10版读书笔记之Chap5(3)——Object类及其equals、hashCode与toString方法
- 《Java核心技术》第10版读书笔记之Chap5(5)——Java中变参函数以及枚举类的原理与使用
- 《Java核心技术》第10版读书笔记之Chap5(2)——方法调用过程、final、类型转换、abstract与访问标识符
- java基本数据类型与字符串之间的转换(基本数据类型、对象封装类、自动装箱、自动拆箱)
- 【JAVA学习】java基本数据类型与字符串之间的转换(基本数据类型、对象封装类、自动装箱、自动拆箱)
- java语言基础(59)——jdk5自动装箱和拆箱(基本数据类型与包装类之间的转换)
- 基本数据类型的自动拆箱与装箱
- 11 jdk5基本数据类型的自动拆箱与装箱
- Java中基本数据类型的自动拆箱和装箱
- Java中基本数据类型的自动拆箱和装箱
- Java中基本数据类型的自动拆箱和装箱
- 高新技术--java基本数据类型的自动装箱与拆箱与枚举
- JAVA——基本数据类型对象包装类/自动装箱
- Java支持的基本数据类型及自动装箱、拆箱
- JAVA进阶之旅(一)——增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法
- Java基本类型的自动装箱与自动拆箱
- Firefox浏览器安装Selenium IDE插件
- VM安装ubuntu出错二进制与此平台上的长模式不兼容
- JAVA中的序列化
- bzoj 1264: [AHOI2006]基因匹配Match
- CentOS、Ubuntu、Debian三个linux比较异同
- 《Java核心技术》第10版读书笔记之Chap5(4)——基本数据类型的Wrapper类、自动拆箱与装箱及过程中的坑
- Windows环境下本地数据源Mnist的Tensorflow实例(Python3.6)
- C语言编写简单病毒
- 水平跑马灯TextView
- 写给大数据开发初学者的话 | 附教程
- java的动态代理机制详解
- python中从str中提取元素到list以及将list转换为str
- 【angular】you have to be inside an Angular CLI project in order to use the serve command
- C语言操作符总结