0
点赞
收藏
分享

微信扫一扫

JDK源码——基本数据类型源码


摘要

本文主要介绍Java中自动拆箱与自动装箱的有关知识。可能初学者对于这个根本就没有听过。这样的问题在当今的校招面试和社招面试中也是很常见的问题。主要是考察你对java的源码是否有深入的了解,为了更好的帮助大家在面试的过程中回答该问题,本博文将详细的解答该问题。

一、基本数据类型

Java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为变量的初始化。基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型。它们是我们编程中使用最频繁的类型。

Java基本类型共有八种,基本类型可以分为三类:

字符类型

​char​

布尔类型

​boolean​

数值类型

​byte​​​、​​short​​​、​​int​​​、​​long​​​、​​float​​​、​​double​

二、基本数据类型有什么好处

我们都知道在Java语言中,​​new​​一个对象是存储在堆里的,我们通过栈中的引用来使用这些对象;所以,对象本身来说是比较消耗资源的。对于经常用到的类型,如int等,如果我们每次使用这种变量的时候都需要new一个Java对象的话,就会比较笨重。所以,和C++一样,Java提供了基本数据类型,这种数据的变量不需要使用new创建,他们不会在堆上创建,而是直接在栈内存中存储,因此会更加高效。

三、整型的取值范围

Java中的整型主要包含​​byte​​​、​​short​​​、​​int​​​和​​long​​这四种,表示的数字范围也是从小到大的,之所以表示范围不同主要和他们存储数据时所占的字节数有关。

整型的这几个类型中,

  • byte:byte用1个字节来存储,范围为-128(-2^7)到127(2^7-1),在变量初始化的时候,byte类型的默认值为0。
  • short:short用2个字节存储,范围为-32,768 (-2^15)到32,767 (2^15-1),在变量初始化的时候,short类型的默认值为0,一般情况下,因为Java本身转型的原因,可以直接写为0。
  • int:int用4个字节存储,范围为-2,147,483,648 (-2^31)到2,147,483,647 (2^31-1),在变量初始化的时候,int类型的默认值为0。
  • long:long用8个字节存储,范围为-9,223,372,036,854,775,808 (-2^63)到9,223,372,036, 854,775,807 (2^63-1),在变量初始化的时候,long类型的默认值为0L或0l,也可直接写为0。

3.1 超出范围怎么办

上面说过了,整型中,每个类型都有一定的表示范围,但是,在程序中有些计算会导致超出表示范围,即溢出。如以下代码:

int i = Integer.MAX_VALUE;
int j = Integer.MAX_VALUE;

int k = i + j;
System.out.println("i (" + i + ") + j (" + j + ") = k (" + k + ")");

输出结果:i (2147483647) + j (2147483647) = k (-2)

这就是发生了溢出,溢出的时候并不会抛异常,也没有任何提示。所以,在程序中,使用同类型的数据进行运算的时候,一定要注意数据溢出的问题。

四、包装类型

Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。包装类均位于java.lang包,包装类和基本数据类型的对应关系如下表所示:

基本数据类型

包装类

byte

Byte

boolean

Boolean

short

Short

char

Character

int

Integer

long

Long

float

Float

double

Double

4.1 为什么需要包装类 

这个问题,其实前面已经有了答案,因为Java是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将int 、double等类型放进去的。因为集合的容器要求元素是Object类型。为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。

4.2 拆箱与装箱

那么,有了基本数据类型和包装类,肯定有些时候要在他们之间进行转换。比如把一个基本数据类型的int转换成一个包装类型的Integer对象。我们认为包装类是对基本类型的包装,所以,把基本数据类型转换成包装类的过程就是打包装,英文对应于boxing,中文翻译为装箱。反之,把包装类转换成基本数据类型的过程就是拆包装,英文对应于unboxing,中文翻译为拆箱。

/**
* 代码解读 1:
* 1.a1 = 200,底层会自动进行装箱操作
* 2.底层会new Integer(),重新分配内存地址
* 3.'=='比较的是引用地址(比较的是新内存地址)
*/
int a1 = 200;
int b1 = 200;
// 所以返回值:true
System.out.println(a1 == b1);

/**
* 1. int的缓存范围值是-128到127
* 2. 当a1=200时,会把int转为包装类(Integer),此时底层会new Integer(),重新分配内存地址
* 3. '=='比较的是引用地址,a1和a2都会进行装箱操作,已经new了新的地址,所有返回为false
*/

/**
* 代码解读 2:
* 1.a2 = 200时,底层会交易是否缓存范围之外,缓存之内外,会开辟新的存储空间
* 2.'=='比较的是引用地址(比较的是新内存地址)
*/

Integer a2 = 200;
Integer b2 = 200;
// 所以返回值:false
System.out.println(a2 == b2);

public static void main(String[] args) {
//基本数据类型的比较
int num1 = 10;
int num2 = 10;
System.out.println(num1 == num2); //true

//引用数据类型的比较
//String类(重写了equals方法)中==与equals的比较

String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); //true,比较地址值:内容相同,因为常量池中只有一个“hello”,所以它们的地址值相同
System.out.println(s1.equals(s2));//true,比较内容:内容相同,因为常量池中只有一个“hello”,所以它们的地址值相同
System.out.println(s1.equals("hello")); //true


String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3 == s4); //false,比较地址值:s3和s4在堆内存中的地址值不同
System.out.println(s3.equals(s4)); //true,比较内容:内容相同

//没有重写equals方法的类中==与equals的比较
People p1 = new People();
People p2 = new People();
People p = p2;
System.out.println(p1);//People@135fbaa4
System.out.println(p2);//People@45ee12a7
System.out.println(p); //People@45ee12a7
System.out.println(p1.equals(p2)); //false,p1和p2的地址值不同
System.out.println(p.equals(p2)); //true,p和p2的地址值相同
}

面试问题有: 

  • int的默认缓存范围值是-128到127之间,
  • 当变量值大于等于缓存范围值时,此时底层会new Integer(),重新分配内存地址
  • '=='比较的是引用地址
  • 堆:用来存储程序中的一些对象,比如你用new关键字创建的对象,它就会被存储在堆内存中,但是这个对象在堆内存中的首地址会存储在栈中。
  • 栈:在jvm中栈用来存储一些对象的引用、局部变量以及计算过程的中间数据,在方法退出后那么这些变量也会被销毁。它的存储比堆快得多,只比CPU里的寄存器慢。栈默认内存:1M

“==”和equals 最大的区别是

  • “==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值
  • equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。string对quals()方法进行了重写。

博文参考​​​​​​​

《JDK源码分析》

举报

相关推荐

0 条评论