Java基础(2)- 基本数据类型与其包装类

对应关系

  上一篇博文中我已经在使用包装类,说明了其对应基本数据类型的一些属性,我们直接上他们之间的对应关系:

基本数据类型包装类
booleanBoolean
byteByte
shortShort
charCharacter
intInteger
longLong
floatFloat
doubleDounle

两者区别

  我个人觉得两者最主要的区别是:包装类是引用数据类型而另一个是基本数据类型。

结构

  1. 基本数据类型有且仅有一个数值
  2. 包装类是一个对象。除了数值,还有其特有的属性(成员变量)和方法

默认值

  1. 基本数据类型boolean默认值为false,其他默认值为0其中char中的0表示空格
  2. 包装类的默认值都为null

内存存储位置

  1. 基本数据类型在方法中定义的非全局基本数据类型变量的具体内容是存储在栈中
  2. 引用数据类型其具体内容都是存放在堆中的,而栈中存放的是其具体内容所在内存的地址

在这里插入图片描述

值传递方式

  1. 基本数据类型是数值传递
  2. 引用数据类型是引用传递(指针传递)

两者互相转换

  Jdk1.5之前,基本数据类型要转换成包装类需要调用包装类的valueOf方法。以int为例,则是java.lang.Integer.valueOf(int)。而由Integer转化成int又需要调用java.lang.Integer.intValue()
  从Jdk1.5之后,基本数据类型可以直接赋值给对应的包装类,非空包装类也可以直接赋值给对应的基本数据类型。null的包装类直接赋值给基本数据类型会抛出java.lang.NullPointerException
  为什么Jdk1.5之后就可以通过直接赋值的方式完成转换呢?实际上这个就是我们经常提及的自动拆装箱。自动拆装箱其实是Java中的一个语法糖,实际java文件在编辑后会自动调用valueOfintValue方法。

  看下面的简单例子:

public static void main(String[] args) {
	Integer a = 100;
    int b = a;
}

  在eclipse自带的反编译插件看下这段代码编译后的class:

public static void main(java.lang.String[] args);
     0  bipush 100
     2  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [16]
     5  astore_1 [a]
     6  aload_1 [a]
     7  invokevirtual java.lang.Integer.intValue() : int [22]
    10  istore_2 [b]
    11  return
      Line numbers:
        [pc: 0, line: 5]
        [pc: 6, line: 6]
        [pc: 11, line: 7]
      Local variable table:
        [pc: 0, pc: 12] local: args index: 0 type: java.lang.String[]
        [pc: 6, pc: 12] local: a index: 1 type: java.lang.Integer
        [pc: 11, pc: 12] local: b index: 2 type: int
}

  虽然这个反编译代码看着不直观,但是我们也可以清楚的看到在标注的第2行和第7行其分别调用了valueOfintValue方法。

数据缓存

  这部分是我们经常会忽视的内容。我们直接上例子:

public static void main(String[] args) {
	Integer a = 100;
	Integer b = 100;
	Integer c = new Integer(100);
	
	Integer d = 200;
	Integer e = 200;
	
	System.out.println(a == b);
	System.out.println(b == c);
	System.out.println(d == e);
}

这个代码运行出来的结果是什么?

true
false
false

为什么会出来这个结果?a == btrue为什么d == e又是false
答案我们还是要从源码中找,这边赋值是一个自动装箱的过程我们直接看下对应的装箱方法:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

  可以看到当int值在最小值(-128)和最大值(默认是127)之间时会直接取得缓存数组中的值。再这范围之外的都会重新new一个Integer
  所以上面的结果也好理解了,100在缓存范围内所以ab实际是同一个对象故其内存地址实际是一个从而结果就是true。而200是在缓存之外所以是两个新的对象对应了两个内存地址,自然就是false
  b == cfalse,说明直接new出的不会走缓存。从源码中会看到其构造方法只是做了一个简单的处理:

public Integer(int value) {
    this.value = value;
}

  除了Integer还有那些包装类也有缓存,通过源码我们得到下面结论:

类型是否有缓存缓存范围
Booleantrue/false
Byte-128~127
Short-128~127
Character0~127
Integer-128~127(默认)
Long-128~127
Float×-
Double×-

其他

  Java作为一个面向对象的语言其包装类已经拥有了基本数据类型的全部功能了为什么还要基本数据类型?
  对于这个问题顶级大佬们有过很多讨论,而保留的原因主要是因为性能:

  • 包装类比基本基本数据类型占用更多的内存空间
  • 基本数据类型使用的是栈内存要比堆内存快的多
  • CPU能直接支持基本数据类型的四则运算和位运算

最后再上一个小问题(这个问题应该上一篇博文留较好):

下面程序输出结果是什么?
public static void main(String[] args) {
	System.out.println((Integer.MAX_VALUE + 1) == Integer.MIN_VALUE);
	System.out.println(Integer.MIN_VALUE - 1 == Integer.MAX_VALUE);
}

A : false false                B : true true
C : 编译错误                    D : 运行错误

答案在下次揭晓。感谢大家的阅读也欢迎您把这篇文章分享给更多的朋友一起阅读!本文有理解错误或存在误导性的地方欢迎私信指出,谢谢大家!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值