‹2› Java面试必备知识点:『基本数据结构和包装类』

数据类型

Java 包含 8 种基本数据类型

  • 布尔型:boolean
  • 整数型:byte、short、int、long
  • 浮点型:float、double
  • 字符型:char

除 char 的包装类 Character 和 int 的包装类 Integer 之外,其他基本数据类型的包装类只需要首字母大写即可。包装类的作用和特点,本文下半部分详细讲解。
在这里插入图片描述
我们可以在代码中,查看某种类型的取值范围,代码如下:

// Byte 取值:-128 ~ 127
String.format("Byte 取值:%d ~ %d", Byte.MIN_VALUE, Byte.MAX_VALUE);

// Int 取值:-2147483648 ~ 2147483647
String.format("Int 取值:%d ~ %d", Integer.MIN_VALUE, Integer.MAX_VALUE);

包装类型的特性有哪些?

因为 Java 的设计思想是万物既对象,有很多时候我们需要以对象的形式操作某项功能,比如说获取哈希值(hashCode)或获取类(getClass)等

  • 功能丰富包装类本质上是一个对象,对象就包含有属性和方法。

    • 比如 hashCode()、getClass() 、max()、min() 等。
  • 可定义泛型类型参数:包装类可以定义泛型,而基本类型不行。

  • 序列化:因为包装类都实现了 Serializable 接口,所以包装类天然支持序列化和反序列化。

  • 类型转换:包装类提供了类型转换的方法,可以很方便的实现类型之间的转换。

    • 比如 shortValue()、longValue()、floatValue()、doubleValue()、toString() 等。
  • 高频区间的数据缓存:此特性为包装类很重要的用途之一,用于高频区间的数据缓存。

数据转换的方法有哪些?

Wrapper 表示所有包装类; Type 表示包装类对应的基本数据类型;types 表示所有基本数据类型。

  • 装箱
    • 构造方法 new $Wrapper($Type/String),例如 new Integer(int/String)
    • 静态方法 $Wrapper.valueOf($Type/String),例如 Integer.valueOf(int/String)
  • 拆箱
    • 成员方法 $typesValue(),例如 intValue()、floatValue()...
  • 字符串
    • 静态方法 $Wrapper.parse$Type(String),例如 Integer.parseInt(String)
    • 成员方法 toString()

如图所示:
在这里插入图片描述

高频缓存区是什么?

在缓存区内的数字,会直接复用已有对象,在这区间之外的数字才会在堆上产生。

各包装类高频区域的取值范围:

  • Float 和 Double 不会有缓存,其他包装类都有缓存。
  • Boolean:使用静态 final 定义,就会返回静态值
  • Character:缓存区 0~127
  • Byte:缓存区 -128~127
  • Short:缓存区 -128~127
  • Integer:缓存区 -128~127
  • Long:缓存区 -128~127

我们使用 == 对 Integer 进行验证,代码如下:

// Integer 高频区缓存范围 -128~127
Integer num1 = 127;
Integer num2 = 127;
System.out.println(num1 == num2); // true
Integer num3 = 128;
Integer num4 = 128;
System.out.println(num3 == num4); // false

由于上面赋值时使用了自动装箱,也就是自动调用了 valueOf 方法,所以我们查看 valueOf 方法的源码 :

public static Integer valueOf(int i) {
	if (i >= IntegerCache.low && i <= IntegerCache.high)
      	// 高频区域的数值会直接使用已有对象
		return IntegerCache.cache[i + (-IntegerCache.low)];
    // 非高频区域的数值会重新 new 一个新的对象
	return new Integer(i);
}

包装类的非高频区数据会在堆上产生(128),高频区则会复用缓存池中的已有对象(127),而这样会导致同样的代码,会因为取值的不同产生两种截然不同的结果。所以,推荐所有包装类对象之间的值比较使用 equals() 方法。

Integer itg3 = 128;
Integer itg4 = 128;
System.out.println(itg3 == itg4); // false
System.out.println(itg.equals(itg)); // true

比较 的问题

1.以下 Integer 代码输出的结果是?

Integer age = 10;
Integer age2 = 10;
Integer age3 = 133;
Integer age4 = 133;
System.out.println((age == age2) + "," + (age3 == age4));

true,false

2.以下 Double 代码输出的结果是?

Double num = 10d;
Double num2 = 10d;
Double num3 = 133d;
Double num4 = 133d;
System.out.println((num == num2) + "," + (num3 == num4));

false,false

3.以下程序输出结果是?

int i = 100;
Integer j = new Integer(100);
System.out.println(i == j);
System.out.println(j.equals(i));

true,true

题目分析:有人认为这和 Integer 高速缓存有关系,但你发现把值改为 10000 结果也是 true,true,这是因为 **Integer 和 int 比较时,会自动拆箱为 int **。相当于两个 int 比较,值一定是 true,true

4.以下程序执行的结果是?

Integer i1 = new Integer(10);
Integer i2 = new Integer(10);
Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf(10);
System.out.println(i1 == i2);
System.out.println(i2 == i3);
System.out.println(i3 == i4);

A:false,false,false
B:false,false,true
C:false,true,true
D:true,false,false

答:B

题目解析:new Integer(10) 每次都会创建一个新对象,Integer.valueOf(10) 则会使用缓存池中的对象

类型转换 的问题

1.以下程序执行的结果是?

Set<Short> set = new HashSet<>();
for (short i = 0; i < 5; i++) {
    set.add(i);
    set.remove(i - 1);
}
System.out.println(set.size());

A:1
B:0
C:5
D:以上都不是

题目解析:C,byte和short型在计算时会自动转换为int型计算,remove() 的时候在集合中找不到 Int 类型的数据,所以就没有删除任何元素,执行的结果就是 5。

2.以下程序哪一句会报错?

short s=2;s=s+1;
short s=2;s+=1;

答:s=s+1 会报错,s+=1 不会报错,因为 byte和short型在计算时会自动转换为int型计算,所以会报错,而 s+=1 还是原来的 short 类型,所以不会报错。

3.以下程序哪一句会报错?

byte a1 = 2, a2 = 4, a3;
short s = 16;
a2 = s;
a3 = a1 * a2;

第3行,数值型变量在默认情况下为Int型

第4行,byte和short型在计算时会自动转换为int型计算,结果也是int 型。

4.以下语句会报错吗?

float f1 = 0.1f;
float f2 = 1;
float f3 = 0.1;

f1+=0.1f;
f1=f1+0.1f;

f1+=1;
f1=f1+1;

f1+=0.1;
f1=f1+0.1;

答:第3行和第12行会报错,因为值 0.1 是 double 类型,float 类型级别小于 double 类型

第6行 f1=0.3,第9行 f1=2.3,第11行 f1=2.3999999。

包装类 的问题

1.基本类 int 和包装类 Integer,在 -128~127 之间都会复用已有的缓存对象,这种说法正确吗?

答:不正确,只有包装类高频区域数据才有缓存

2.包装类 Double 和 Integer 一样都有高频区域数据缓存,这种说法正确吗?

答:不正确,基本数据类型的包装类只有 Double 和 Float 没有高频区域的缓存。

3.包装类的值比较要使用什么方法?

答:包装类因为有高频区域数据缓存,所以推荐使用 equals() 方法进行值比较。

4.包装类有哪些功能?

答:包装类提供的功能有以下几个。

  • 功能丰富:包装类包含了有 hashCode、getClass 、max、min 等方法;
  • 可定义泛型类型参数:例如 List list = new ArrayList<>(); ;
  • 序列化:包装类实现了 Serializable 接口,所以包装类天然支持序列化和反序列化;
  • 类型转换:包装类提供了方便的类型转换方法,比如 Integer 的 parseInt() 方法;
  • 高频区域数据缓存:高频区域可使用已有的缓存对象。

5.选择包装类还是基本类的原则有哪些?

答:我们知道正确的使用包装类,可以提供程序的执行效率,可以使用已有的缓存,一般情况下选择基本数据类型还是包装类原则有以下几个。

所有 POJO 类属性必须使用包装类
RPC 方法返回值和参数必须使用包装类;
所有局部变量推荐使用基本数据类型

基本数据类型 的问题

1.泛型可以为基本类型吗?为什么?

答:泛型不能使用基本数据类型。泛型在 JVM(Java虚拟机)编译的时候会类型檫除,比如代码 List<Integer> list 在 JVM 编译的时候会转换为 List list因为泛型是在 JDK 5 时提供的,而 JVM 的类型檫除是为了兼容以前代码的一个折中方案,类型檫除之后就变成了 Object,而 Object 不能存储基本数据类型,但可以使用基本数据类型对应的包装类,所以像 List<int> list 这样的代码是不被允许的,编译器阶段会检查报错,而 List<Integer> list 是被允许的。

2.基本数据类型在 JVM 中一定存储在栈中吗?为什么?

答:基本数据类型不一定存储在栈中,因为基本类型的存储位置取决于声明的作用域,来看具体的解释。

  • 当基本数据类型为局部变量的时候,比如在方法中声明的变量,则存放在方法栈中的,当方法结束系统会释放方法栈,在该方法中的变量也会随着栈的销毁而结束,这也是局部变量只能在方法中使用的原因;
  • 当基本数据类型为全局变量的时候,比如类中的声明的变量,则存储在堆上,因为全局变量不会随着某个方法的执行结束而销毁。

3.char 变量能不能存贮一个中文汉字?为什么?

答:char 变量可以存贮一个汉字,因为 Java 中使用的默认编码是 Unicode ,一个 char 类型占 2 个字节(16 bit),所以放一个中文是没问题的。

计算 的问题

1.以下程序执行的结果是?

final int iMax = Integer.MAX_VALUE;
System.out.println(iMax + 1);

A:2147483648
B:-2147483648
C:程序报错
D:以上都不是

题目解析:整数在内存中使用的是补码的形式表示,最高位是符号位 0 表示正数,1 表示负数。当执行 +1 时,最高位就变成了 1,结果就成了 -2147483648。

Integer.MAX_VALUE = 2147483647 = 231-1,二进制位:0111 1111 1111 1111 1111 1111 1111 1111;

Integer.MIN_VALUE = -2147483648 = 2-31,二进制位: 1000 0000 0000 0000 0000 0000 0000 0000;

所以,由此可知 Integer.MAX_VALUE + 1 = Integer.MIN_VALUE

2.以下程序执行的结果是? 返回值是多少?

System.out.println( 3*0.1==0.3 );

答:返回值为:false。因为有些浮点数不能完全精确的表示出来

如下代码:System.out.println(3 * 0.1);,返回的结果是:0.30000000000000004。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值