首页 > 其他分享 >当涉及到基本数据类型和包装类时,一些你需要了解、可能容易被忽略的细节。(附面试题)

当涉及到基本数据类型和包装类时,一些你需要了解、可能容易被忽略的细节。(附面试题)

时间:2023-05-26 23:34:35浏览次数:43  
标签:面试题 缓存 类时 包装 数据类型 println 128 Integer true

基本数据类型

Java 基本数据按类型可以分为四大类:布尔型、整数型、浮点型、字符型,这四大类包含 8 种基本数据类型。

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

8 种基本类型取值如下:

数据类型

代表含义

默认值

取值

包装类

boolean

布尔型

false

0(false) 到 1(true)

Boolean

byte

字节型

(byte)0

﹣128 到 127

Byte

char

字符型

'\u0000'(空)

'\u0000' 到 '\uFFFF'

Character

short

短整数型

(short)0

-215215 到 215215


﹣1

Short




int

整数型

0

﹣231231 到 231231﹣1

Integer

long

长整数型

0L

﹣263263 到 263263﹣1

Long

float

单浮点型

0.0f

1.4e-45 到 3.4e+38

Float

double

双浮点型

0.0d

4.9e-324 到 1.798e+308

Double

除 char 的包装类 Character 和 int 的包装类 Integer 之外,其他基本数据类型的包装类只需要首字母大写即可。包装类的作用和特点,本文下半部分详细讲解。

我们可以在代码中,查看某种类型的取值范围,代码如下:

public static void main(String[] args) {
    // Byte 取值:-128 ~ 127
    System.out.println(String.format("Byte 取值:%d ~ %d", Byte.MIN_VALUE, Byte.MAX_VALUE));
    // Int 取值:-2147483648 ~ 2147483647
    System.out.println(String.format("Int 取值:%d ~ %d", Integer.MIN_VALUE, Integer.MAX_VALUE));
}

包装类型

我们知道 8 种基本数据类型都有其对应的包装类,因为 Java 的设计思想是万物既对象,有很多时候我们需要以对象的形式操作某项功能,比如说获取哈希值(hashCode)或获取类(getClass)等。

那包装类特性有哪些?

1. 功能丰富

包装类本质上是一个对象,对象就包含有属性和方法,比如 hashCode、getClass 、max、min 等。

2. 可定义泛型类型参数

包装类可以定义泛型,而基本类型不行。

比如使用 Integer 定义泛型,代码:

List<Integer> list = new ArrayList<>();

如果使用 int 定义就会报错,代码:

List list = new ArrayList<>();  // 编译器代码报错

3. 序列化

因为包装类都实现了 Serializable 接口,所以包装类天然支持序列化和反序列化。比如 Integer 的类图如下:

当涉及到基本数据类型和包装类时,一些你需要了解、可能容易被忽略的细节。(附面试题)_面试题

4. 类型转换

包装类提供了类型转换的方法,可以很方便的实现类型之间的转换,比如 Integer 类型转换代码:

String age = "18";
int ageInt = Integer.parseInt(age) + 2;
// 输出结果:20
System.out.println(ageInt);

5. 高频区间的数据缓存

此特性为包装类很重要的用途之一,用于高频区间的数据缓存,以 Integer 为例来说,在数值区间为 -128~127 时,会直接复用已有对象,在这区间之外的数字才会在堆上产生。

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

public static void main(String[] args) {
        // Integer 高频区缓存范围 -128~127
        Integer num1 = 127;
        Integer num2 = 127;
        // Integer 取值 127 == 结果为 true(值127 num1==num2 => true)
        System.out.println("值127 num1==num2 => " + (num1 == num2));
        Integer num3 = 128;
        Integer num4 = 128;
        // Integer 取值 128 == 结果为 false(值128 num3==num4 => false)
        System.out.println("值128 num3==num4 => " + (num3 == num4));
    }

从上面的代码很明显可以看出,Integer 为 127 时复用了已有对象,当值为 128 时,重新在堆上生成了新对象。

为什么会产生高频区域数据缓存?我们查看源码就能发现“线索”,源码版本 JDK8,源码如下:

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

由此可见,高频区域的数值会直接使用已有对象,非高频区域的数值会重新 new 一个新的对象。

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

  • Boolean:使用静态 final 定义,就会返回静态值
  • Byte:缓存区 -128~127
  • Short:缓存区 -128~127
  • Character:缓存区 0~127
  • Long:缓存区 -128~127
  • Integer:缓存区 -128~127

包装类的注意事项

  • int 的默认值是 0,而 Integer 的默认值是 null。
  • 推荐所有包装类对象之间的值比较使用 equals() 方法,因为包装类的非高频区数据会在堆上产生,而高频区又会复用已有对象,这样会导致同样的代码,因为取值的不同,而产生两种截然不同的结果。代码示例:
public static void main(String[] args) {
    // Integer 高频区缓存范围 -128~127
    Integer num1 = 127;
    Integer num2 = 127;
    // Integer 取值 127 == 结果为 true(值127 num1==num2 => true)
    System.out.println("值127 num1==num2 => " + (num1 == num2));
    Integer num3 = 128;
    Integer num4 = 128;
    // Integer 取值 128 == 结果为 false(值128 num3==num4 => false)
    System.out.println("值128 num3==num4 => " + (num3 == num4));
    // Integer 取值 128 equals 结果为 true(值128 num3.equals(num4) => true)
    System.out.println("值128 num3.equals(num4) => " + num3.equals(num4));
}
  • Float 和 Double 不会有缓存,其他包装类都有缓存。
  • Integer 是唯一一个可以修改缓存范围的包装类,在 VM optons 加入参数:

-XX:AutoBoxCacheMax=666 即修改缓存最大值为 666

示例代码如下:

public static void main(String[] args) {
    Integer num1 = -128;
    Integer num2 = -128;
    System.out.println("值为-128 => " + (num1 == num2));
    Integer num3 = 666;
    Integer num4 = 666;
    System.out.println("值为666 => " + (num3 == num4));
    Integer num5 = 667;
    Integer num6 = 667;
    System.out.println("值为667 => " + (num5 == num6));
}

执行结果如下:

值为-128 => true
值为666 => true
值为667 => false

由此可见将 Integer 最大缓存修改为 666 之后,667 不会被缓存,而 -128~666 之间的数都被缓存了。

相关面试题

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));

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

答:A

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

4. 以下程序执行的结果是?
final int iMax = Integer.MAX_VALUE;
System.out.println(iMax + 1);

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

答:B

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

5. 以下程序执行的结果是?
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:以上都不是

答:5

题目解析:Short 类型 -1 之后转换成了 Int 类型,remove() 的时候在集合中找不到 Int 类型的数据,所以就没有删除任何元素,执行的结果就是 5。

6. short s=2;s=s+1; 会报错吗?short s=2;s+=1; 会报错吗?

答:s=s+1 会报错,s+=1 不会报错,因为 s=s+1 会导致 short 类型升级为 int 类型,所以会报错,而 s+=1 还是原来的 short 类型,所以不会报错。

7. float f=3.4; 会报错吗?为什么?

答:会报错,因为值 3.4 是 double 类型,float 类型级别小于 double 类型,所以会报错。如下图所示:

当涉及到基本数据类型和包装类时,一些你需要了解、可能容易被忽略的细节。(附面试题)_Java_02

8. 为什么需要包装类?

答:需要包装类的原因有两个。

① Java 的设计思想是万物既对象,包装类体现了面向对象的设计理念; ② 包装类包含了很多属性和方法,比基本数据类型功能多,比如提供的获取哈希值(hashCode)或获取类(getClass)的方法等。

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

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

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

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

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

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

12. 包装类有哪些功能?

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

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

详见正文“包装类型”部分内容。

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

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

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

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

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

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

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

  • 当基本数据类型为局部变量的时候,比如在方法中声明的变量,则存放在方法栈中的,当方法结束系统会释放方法栈,在该方法中的变量也会随着栈的销毁而结束,这也是局部变量只能在方法中使用的原因;
  • 当基本数据类型为全局变量的时候,比如类中的声明的变量,则存储在堆上,因为全局变量不会随着某个方法的执行结束而销毁。
16. 以下程序执行的结果是?
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) 则会使用缓存池中的对象。

17. 3*0.1==0.3 返回值是多少?

答:返回值为:false。

题目解析:因为有些浮点数不能完全精确的表示出来,如下代码:

System.out.println(3 * 0.1);

返回的结果是:0.30000000000000004。

标签:面试题,缓存,类时,包装,数据类型,println,128,Integer,true
From: https://blog.51cto.com/u_16013021/6359591

相关文章

  • 深入理解字符串(附面试题)
    字符串介绍字符串是程序开发当中,使用最频繁的类型之一,有着与基础类型相同的地位,甚至在JVM(Java虚拟机)编译的时候会对字符串做特殊的处理,比如拼加操作可能会被JVM直接合成为一个最终的字符串,从而到达高效运行的目的。1String特性String是标准的不可变类(immutable),对它的任何改......
  • Java 中的运算符和流程控制(附面试题)
    算术运算符Java中的算法运算符,包括以下几种:算术运算符名称举例+加法1+2=3-减法2-1=1*乘法2*3=6/除法24/8=3%求余24%7=3++自增1inti=1;i++--自减1inti=1;i--我们本讲要重点讲的是“++”和“--”,其他的算术运算符相对比较简单直观,本讲就不花精力去讲解了,之所以要把“++”和......
  • 全面掌握 Java 中的异常处理(附面试题)
    在程序开发中,异常处理也是我们经常使用到的模块,只是平常很少去深究异常模块的一些知识点。比如,try-catch处理要遵循的原则是什么,finally为什么总是能执行,try-catch为什么比较消耗程序的执行性能等问题,我们本讲内容都会给出相应的答案,当然还有面试中经常被问到的异常模块的一些面......
  • 玩转时间操作(附面试题)
    在JDK8之前,Java语言为我们提供了两个类用于操作时间,它们分别是:java.util.Date和java.util.Calendar,但在JDK8的时候为了解决旧时间操作类的一些缺陷,提供了几个新的类,用于操作时间和日期,它们分别是:LocalTime、LocalDateTime、Instant,都位于java.time包下。时间的操作在我......
  • 数据类型转换校验核心类---DataBinder,详细讲述一下其运行机制
    下面就是其运行机制的示意图 简单一句话就是把请求中参数信息绑定到目标方法的参数上。数据绑定是参数解析过程中的一部分。SpringMVC通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中①数据绑定过程中,获取到请求中的数据后向目标对象进行绑定,那么这个阶......
  • geotools判断geom的数据类型
    参考1:https://blog.csdn.net/ylfmsn/article/details/107487776参考2:https://wenku.baidu.com/view/ad2bd16ae618964bcf84b9d528ea81c758f52ea0.html......
  • 数据类型
    publicclassdemoo{publicstaticvoidmain(String[]args){Stringa="hello";intnum=10;System.out.println(a);System.out.println(num);//八大数据基本类型一字节(byte)=八位(bit)//整数,int最常用intnum1......
  • 八大基本数据类型
    publicclassdemoo{publicstaticvoidmain(String[]args){Stringa="hello";intnum=10;System.out.println(a);System.out.println(num);//八大数据基本类型一字节(byte)=八位(bit)//整数,int最常用intnum1......
  • kubenetes 面试题汇总1
    什么是Kubernetes?答:Kubernetes是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它提供了一种简单而有效的方式来管理大规模的容器化应用程序,并且可以在不同的基础设施上运行,包括公共云、私有云和混合云。Kubernetes中的Pod是什么?它有什么作用?答:Pod是Kubernetes......
  • Selenium自动化测试面试必备:高频面试题及答案整理
    自动化测试已经成为现代软件测试中不可或缺的一部分。在自动化测试中,Selenium是最受欢迎的工具之一,因为它可以模拟用户与Web应用程序的交互。因此,对于许多测试工程师来说,熟练掌握Selenium框架是非常重要的。如果你正在寻找一份自动化测试工作,那么你可能会被问到一些关于Selenium的......