小林coding面试题笔记(二)

1. Java的基本数据类型

Java支持两类数据类型:基本数据类型引用数据类型
基本数据类型共有8种,分为以下三类:

  1. 数值型:包括整数类型(byteshortintlong)和浮点类型(floatdouble)。
  2. 字符型char
  3. 布尔型boolean

以下是8种基本数据类型的默认值、位数、取值范围等信息:

数据类型占用大小(字节)位数取值范围默认值描述
byte18-128 到 1270最小的整数类型,适合节省内存。
short216-32768 到 327670较少使用,适合小范围整数。
int432-2147483648 到 21474836470最常用的整数类型。
long864-9223372036854775808 到 92233720368547758070L表示非常大的整数,需加L后缀。
float4321.4E-45 到 3.4028235E380.0f单精度浮点数,需加f后缀。
double8644.9E-324 到 1.7976931348623157E3080.0d双精度浮点数,默认浮点类型。
char216‘\u0000’ 到 ‘\uffff’‘\u0000’表示单个字符,采用Unicode编码。
boolean不明确(理论1位)不明确truefalsefalse用于逻辑判断。

注意事项:

  1. 默认浮点数类型为double,若需声明float型,需加fF后缀。
  2. 默认整数类型为int,若需声明long型,需加lL后缀。
  3. char类型是无符号的,取值范围从0开始。
  4. 包装类:int对应Integerchar对应Character,其他基本类型包装类首字母大写。
  5. boolean类型的大小和存储方式依赖于JVM实现,通常以1位表示,但实际存储可能占用1字节或更多。

2. long和int可以互转吗?

可以,longint可以相互转换:

  • intlong:自动转换,安全无数据丢失。
  • longint:需强制类型转换,可能导致数据丢失或溢出。

示例代码:

1
2
3
4
5
int intValue = 10;
long longValue = intValue; // 自动转换

long longValue2 = 100L;
int intValue2 = (int) longValue2; // 强制类型转换

总结:

  • 小类型转大类型:自动转换。
  • 大类型转小类型:需强制转换,注意数据丢失或溢出。
  • 在实际开发中,尽量避免强制类型转换,尤其是可能导致数据丢失的场景。

3. 数据类型转换方式

常见的类型转换方式:

  1. 自动类型转换(隐式转换):小范围类型自动转换为大范围类型。
    示例:intlongfloatdouble
  2. 强制类型转换(显式转换):大范围类型转换为小范围类型,需显式声明。
    示例:longintdoubleint
  3. 字符串转换:通过Integer.parseInt()Double.parseDouble()等方法将字符串转换为数值类型。
    示例:
    1
    2
    3
    4
    5
    6
    7
    8
        String str = "123";
    int num = Integer.parseInt(str); // 字符串转int
    ```
    4. **数值之间的转换**:通过包装类方法实现,如`Character`、`Integer`等。
    示例:
    ```java
    char c = 'A';
    int ascii = Character.getNumericValue(c); // 字符转ASCII值

4. 类型互转可能出现的问题

  1. 数据丢失:大范围类型转小范围类型时,高位数据可能丢失。
    示例:
    1
    2
    3
    long largeValue = 123456789L;
    int smallValue = (int) largeValue; // 数据丢失
    System.out.println(smallValue); // 输出:-539222987
  2. 数据溢出:小范围类型转大范围类型时,可能填充额外高位空间。
  3. 精度损失:浮点数类型转换时可能丢失精度。
    示例:
    1
    2
    3
    double d = 1.23456789;
    float f = (float) d; // 精度损失
    System.out.println(f); // 输出:1.2345679
  4. 类型不匹配:不兼容类型转换会导致编译或运行时错误。
    示例:
    1
    2
    String str = "abc";
    int num = Integer.parseInt(str); // 抛出NumberFormatException

5. 为什么用BigDecimal而不是double?

double可能出现精度丢失问题,尤其在涉及金钱计算时。
示例:

1
System.out.println(0.05 + 0.01); // 输出:0.060000000000000005

使用BigDecimal可以避免精度问题:

1
2
3
4
BigDecimal num1 = new BigDecimal("0.1");
BigDecimal num2 = new BigDecimal("0.2");
BigDecimal sum = num1.add(num2);
System.out.println("Sum: " + sum); // 输出:0.3

注意:

  1. 使用BigDecimal时,应通过字符串构造,避免浮点数精度丢失。
  2. BigDecimal提供了丰富的API(如add()subtract()multiply()divide()),适合高精度计算。
  3. 在涉及货币、金融等场景时,优先使用BigDecimal

6. 装箱和拆箱是什么?

  • 装箱(Boxing):基本类型转为包装类。
  • 拆箱(Unboxing):包装类转为基本类型。

示例:

1
2
Integer i = 10;  // 自动装箱
int n = i; // 自动拆箱

注意:

  1. 在循环中频繁装箱/拆箱可能影响性能,建议使用基本类型。
  2. 装箱和拆箱是编译器的语法糖,底层通过Integer.valueOf()intValue()实现。

7. 为什么需要Integer?

  1. 对象封装Integer提供了方法(如parseInt())处理int相关数据。
  2. 集合支持:集合类(如ArrayList)只能存储对象,需使用Integer
  3. 泛型支持:泛型只能使用引用类型,需用Integer代替int
  4. 空值支持Integer可以为null,而int不支持空值。

8. Integer相比int的优点

  1. 对象特性Integer是引用类型,可用于集合、泛型等场景。
  2. 自动装箱/拆箱:简化基本类型与对象类型的转换。
  3. 方法支持Integer提供了丰富的方法(如compareTo()toString()等)。

9. 为什么保留int类型?

  1. 性能int操作更高效,内存占用更小(4字节 vs. Integer的16字节)。
  2. 直接存储int变量直接存储数据,无需额外内存分配。
  3. 简单性int适合高性能场景,如循环计数器、数学运算等。

10. Integer的缓存机制

Integer类对-128127范围内的值实现了缓存。
示例:

1
2
3
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // 输出:true

超出范围时,不会复用缓存对象:

1
2
3
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // 输出:false

原因:

  1. 缓存机制通过Integer.valueOf()方法实现。
  2. 缓存范围可通过-XX:AutoBoxCacheMax=<size>调整,默认范围为-128127
  3. 缓存机制提高了小范围整数的性能,但超出范围时会创建新对象。