首页 / JAVA / java源码分析-基本类型和包装类
java源码分析-基本类型和包装类
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java源码分析-基本类型和包装类,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7720字,纯文字阅读大概需要12分钟。
内容图文
![java源码分析-基本类型和包装类](/upload/InfoBanner/zyjiaocheng/601/f3ca2b46bcde44c6b0342b8ef16414df.jpg)
java源码分析-基本类型和包装类
1.类型、值和变量
? java是一种静态类型语言,每个变量和表达式都在编译期就确定了类型。
? java还是一种强类型语言,类型的确定就限定了类该类型变量的值或者表达式返回值的类型。
1.1基本类型和引用类型
? java语言的类型分为两种:基本类型和引用类型;
-
基本类型包括布尔类型boolean和数字类型,其中数字类型包括整数类型byte、short、char、int和long以及浮点数类型float和double。
-
引用类型包括类类型、接口类型和数组类型,另外还有一个特殊的空类型。
1.2变量和值
基本类型和引用类型分别对应简单值和引用值,它们是被存储在变量中的。也就是说,变量可以持有值,不管是基本类型值还是引用类型值。
《java语言规范》中对简单类型有这样的描述:
? 基本类型的变量总是持有简单值,其类型与该基本类型精确匹配。
? 类类型T的变量可以持有空引用,或者是对T类一个T的任意子类的实例的引用。
? 接口类型的变量可以持有空引用,或者是对实现了该接口的任意类的实例的引用。
简单说:基本类型值就是数字值本身,引用类型值是对对象的引用,它们被变量持有。
1.3对象和实例
? 对象是动态创建出来的类类型的实例或者动态创建的数组。
注意:
? 类类型的实例或者数组,所有基本数据类型是没有对象和实例的概念的。
? 引用类型有对象的概念,才会使引用类型值是对对象的引用有了成立的前提。
2.包装类
? 在java中,每一种基本类型都提供了一个对应的包装类,方便对各种类型数据进行操作。
2.1基本类型对应包装类
? 所有的包装类都在java.lang包下面,下表列出了简单类型和包装类的对应关系:
基本类型 | 字节 | 包装类 |
---|---|---|
boolean | 1或4 | Boolean |
byte | 1 | Byte |
char | 2 | Character |
short | 2 | Short |
int | 4 | Integer |
long | 8 | Long |
float | 4 | Float |
double | 8 | Double |
ps:
? boolean是基本数据类型中唯一没有给出具体占用字节数的,因为对于虚拟机来说,不存在boolean类型,boolean类型编译后是由其他类型表示的。boolean类型没有给出精确的定义,《Java虚拟机规范》给出了4个字节,和boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。
2.2Number类
? 在前面我们通过UML类图看到除了Boolean类和Character类,其他的基本类型包装类都继承累Number类。下面我们了解一下Nember这个类是干什么的。
public abstract class Number implements java.io.Serializable
抽象类Number实现类Serializable接口,用来提供序列化功能。它包含如下方法:
这些方法都是用于byte、double、float、long、short、int这几种类型之间的相互转换。例如从int转为long,long转为int等。
有一点:Character、Boolean包装类没有继承Number,但是他们两内部自己实现类对应的方法,用于实现对应功能:
/**
* Returns the value of this {@code Character} object.
* @return the primitive {@code char} value represented by
* this object.
*/
public char charValue() {
return value;
}
2.3自动装箱拆箱
(1)底层实现
? 自动装箱和拆箱是java包装类的一大特性。基本类型通过自动装箱转为对应的包装类;包装类通过自动拆箱转为对应的基础类型。
而这种转换机制是java为我们自动处理的,不需要我们自己做任何操作。下面我们以Integer来演示自动装箱和拆箱是底层是怎么实现的。
例如:
public class IntegerDemo {
public static void main(String[] args) {
int a = 255;
Integer integer = a;
int b = integer;
}
}
以上这段代码是正常的,可以本正常执行。原因就是因为java自动的帮助我们进行了装箱和拆箱的操作。
那这到底是怎么实现的呢?我们通过反编译查看一下反编译后的代码就恍然大悟了:
通过反编译后的代码,我们发现编译器自动修改了我们的代码,用Integer integer = Integer.valueOf(a);替换掉了Integer integer =a;,用int b = integer.intValue();替换掉了int b = integer;
所以:自动装箱使用对应包装类的valueOf()方法来实现;而自动拆箱是通过我们前面说的个包装类继承抽象类Number提供的xxxValue()方法。对于没有继承Number的包装类Charactor和Boolean,它们自身实现xxxValue()方法来实现转换。
验证如下:
char ch = 'a';
Character character = ch;
char ch2 = character;
boolean b1 = true;
Boolean b = b1;
boolean b2 = b;
反编译之后:
(2)自动装箱拆箱场景
1)将基本类型放入包装类:
public static void main(String[] args) {
//将基本类型放入集合中
List<Integer> list = new ArrayList<>();
list.add(12);
list.add(13);
list.add(15);
}
反编译后:
可以发现,当我们将基本类型放入集合中是,java会自动帮我们进行装箱,也就是通过过valueOf()方法进行转换。
2)包装类型与基本类型进行大小比较
//基本类型与包装类进行大小比较
int n1 = 1;
Integer n2 = new Integer(2);
System.out.println(n1 > n2);
反编译:
可以看到当我们使用包装类与基本类型进行大小比较(>、<、==)是,包装类型会被自动拆箱转为对应的基本类型,在进行比较。
3)基本类型与包装类型运算
int a1 = 22;
Integer a2 = new Integer(25);
System.out.println(a1 - a2);
可以发现,包装类在于基本类型进行四则运算时,同样也会自动拆箱,然后再进行运算。
2.4缓存策略及问题
(1)包装类的缓存策略
? 在研究Integer源码时,发现一个有趣的机制,就是各种包装类型都提供类相应的缓存机制。以Integer类为例:
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类的静态内部类,起作用就是作为一个Integer对象的缓存来使用。
private static class IntegerCache { //Integer对象的缓存类,会缓存-127~128之间的int整数对应的Integer对象
static final int low = -128;
static final int high;
static final Integer cache[]; //将数据放入Integer对象数组中
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); //从jvm系统环境中获取最大值
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue); //转为int数值
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]; //创建(high - low) + 1的大小的数组
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++); //创建对应的Integer对象并存入数组
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
? h和cache的初始化实在static代码块中进行。首先会去jvm虚拟机参数java.lang.Integer.IntegerCache.high中获取high的值,如果获取不到,就设定为127,cache数组的长度就是127-(-128)+1 = 256,也就是说这个IntegerCache会缓存256个Integer对象,对应的值从-128到127。如果我们创建的Integer对象的值不在[-128,127]之间,那么就会重新创建一个Integer对象。
? 不同的包装类有着不同的缓存策略:
? 除了Integer外,Byte、Short、Long都有类似地缓存策略并且这几个包装类的默认缓存范围均为[-128,127],但是只有Integer的缓存最大值可以通过参数java.lang.Integer.IntegerCache.high来设置,其他的几个均不能,可以看一下Long的cache实现:
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
就是很简单的初始化数组,没有取参数值的逻辑。
ps: Double和Float是没有缓存的!
(2)缓存带来的问题
? 正是由于包装类的缓存问题,就可能导致某些操作会得到出乎意料的结果。比如两个包装类的比较:
我们知道,==作用于引用类型的对象时,比较的是引用值,包装类也是如此,而要想比较包装类的简单值,就需要使用equals方法:
public static void main(String[] args) {
Integer integer1 = new Integer(100);
Integer integer2 = new Integer(100);
System.out.println(integer1 == integer2);
System.out.println(integer1.equals(integer2));
}
输出结果是false、true,所以在进行包装类型内的简单类型的相等性判断时,需要用equals方法。
但是由于缓存策略,就会出现下面的情况:
public static void main(String[] args) {
Integer integer11 = 100;
Integer integer12 = 100;
System.out.println(integer11 == integer12);
System.out.println(integer11.equals(integer12));
}
输出的是两个true。10处于Integer的默认缓存区间,两个integer1和integer2实际上指向一个对象,所以对于[-128,127]区间内的通过装箱转换得到的Integer对象,==操作符会返回true,不过这个true的意义是说这两个引用指向的是同一个对象。
所以,==对于包装对象来说总是比较引用地址而不是内部简单数据类型的值,最保险的方法就是想比较包装类型内部的简单值时总是使用equals方法。
3.总结
? 本文主要是对基本类型和包装类的一些概念进行了解析,通过源码分些累包装类的一些特性,如自动装箱和拆箱,缓存策略等。
内容总结
以上是互联网集市为您收集整理的java源码分析-基本类型和包装类全部内容,希望文章能够帮你解决java源码分析-基本类型和包装类所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。