JavaSE之基础篇

2023-08-31 八股文
1.如何判断两个BigDecimal是否相等?为什么不能用BigDecimal的equals方法做等值比较?

因为BigDecimal的equals方法和compareTo并不一样,equals方法会比较两部分内容,分别是值(value)和标度(scale),而对于0.1和0.10这两个数字,他们的值虽然一样,但是精度是不一样的,所以在使用equals比较的时候会返回false。

2.BigDecimal(double)和BigDecimal(String)有什么区别?

double是不精确的,所以使用一个不精确的数字来创建BigDeciaml,得到的数字也是不精确的。如0.1这个数字,double只能表示他的近似值0.1000000000000000055511151231257827021181583404541015625

3.Java中的负数取绝对值结果一定是正数吗?

int的取值范围是-231 ~ (231) - 1,即-2147483648 ~ 2147483647;当我们使用abs取绝对值时候,想要取得-2147483648的绝对值,那应该是2147483648。但是,2147483648大于了2147483647,即超过了int的取值范围。这时候就会发生越界。

2147483647用二进制的补码表示是:01111111 11111111 11111111 11111111;这个数+1得到:10000000 00000000 00000000 0000000,这个二进制就是码-2147483648。

解决方法是采用long类型存储,再大就得使用字符串处理了。

4.String、StringBuilder和StringBuffer的区别?
  • 三者都是final, 不允许被继承
  • String是不可变的、StringBuffer线程安全、StringBuilder是非线程安全的
  • 在本质都是char[]字符数组实现
5.String、StringBuilder和StringBuffer的区别?

转换成StringBuilder,使用append函数实现。

6.String为什么设计成不可变的?
  1. 缓存:字符串是使用最广泛的数据结构,大量字符串的创建非常耗费资源,JVM中专门开辟了一部分空间来存储Java字符串,那就是字符串常量池。通过字符串池,两个内容相同的字符串变量,可以从池中指向同一个字符串对象,从而节省了关键的内存资源。之所以可以这么做,主要是因为字符串的不变性。试想一下,如果字符串是可变的,我们一旦修改了s的内容,那必然导致s2的内容也被动的改变了,这显然不是我们想看到的。
  2. 安全性:当我们在程序中传递一个字符串的时候,如果这个字符串的内容是不可变的,那么我们就可以相信这个字符串中的内容。如果是可变的,那么这个字符串内容就可能随时都被修改。那么这个字符串内容就完全不可信了。这样整个系统就没有安全性可言了。
  3. 线程安全:不可变会自动使字符串成为线程安全的,因为当从多个线程访问它们时,它们不会被更改。因为如果线程更改了值,那么将在字符串池中创建一个新的字符串,而不是修改相同的值。因此,字符串对于多线程来说是安全的。
  4. hashcode缓存:由于字符串对象被广泛地用作数据结构,它们也被广泛地用于哈希实现,在对这些散列实现进行操作时,经常调用hashCode()方法。不可变性保证了字符串的值不会改变。因此,hashCode()方法在String类中被重写,以方便缓存,这样在第一次hashCode()调用期间计算和缓存散列,并从那时起返回相同的值。
  5. 性能:因为字符串不可变,所以可以用字符串池缓存,可以大大节省堆内存。由于字符串是应用最广泛的数据结构,提高字符串的性能对提高整个应用程序的总体性能有相当大的影响。
7.String a="ab"; String b="a"+"b"; a==b 吗?

等于,"a"+"b"在编译之后会把字面量直接合在一起。

8.String有长度限制吗?是多少?
  • 有,编译期和运行期不一样
  • 编译时,2^16-1 = 65535
  • 运行时,2^31-1
9.RPC接口返回中,使用基本类型还是包装类?
  • 使用包装类;比如float如果使用基本类型在数据传递或程序运行时报错会默认为0,而不是null;
  • 那么就会产生歧义,返回0,程序无法判断这个0,是错误还是此字段内容就是0; 在接口定义时,应使用下面哪一种?
boolean success
Boolean success
boolean isSuccess
Boolean isSuccess
  • 答案是第一种,作为接口的返回对象的参数,这个字段不应该有不确定的null值,而Boolean类型的默认值是null,而boolean的默认值是false。
  • 定义为基本数据类型如果加is那么它的方法也是isSuccess(), RPC框架在反向解析的时候,以为对应的属性名称是success,导致属性获取不到,进而抛出异常。 异常。
10.常见的字符编码有哪些?有什么区别?

UTF-8、UTF-16等都是Unicode的一种实现方式,GBK是一种中文字符编码,在UTF-8需要3个字节才能表示的汉字到GBK只需要两个字符,因为有一些西文字符或表情等GBK不需要记录。

  • Ascll码只能表示英文,不能表示所有字符,因此出现了Unicode字符集。
  • Unicode是计算机科学领域里的一项业界标准,Unicode虽然统一了全世界字符的编码,但没有规定如何存储;
  • 如果Unicode统一规定,每个符号就要用三个或四个字节表示,因为字符太多只能用这么多字节才能表示完全,英文本来只需要占1个字节,现在也需要四个字节来表示,会产生资源浪费。
  • 为了解决这个问题,就出现了一些中间格式的字符集,即UTF-8(1~4字节)、UTF-16(2~4字节)、UTF-32(4个字节)等
11.什么是SPI,和API有啥区别?
  1. API定义软件组件之间交互的接口,SPI是一种扩展机制,通常用于在应用程序中提供可插拔的实现,调用方可使用SPI其内部实现或自己扩展。
  2. 总结:API用于定义调用接口,而SPI用于定义和提供可插拔的实现方式;API直接调用而SPI可以自己实现或扩展。
12.Java中异常分哪两类,有什么区别?

受检异常和非受检异常,针对受检异常一定要对该异常进行处理(捕获或者向上抛出),否则编译无法通过,例如IO流相关异常。

对于非受检异常来说,一般是运行时异常,继承自RuntimeException。例如空指针、数组越界等

13.以下关于异常处理的代码有哪些问题?
public static void start() throws IOException, RuntimeException {
    throw new RuntimeException("Not able to Start");
}

public static void main(String args[]) {
    BufferedReader br = null;
    try {
        String line;
        br = new BufferedReader(new FileReader("\home\usr\test.java"));
        while ((line = br.readLine()) != null) {
            start();
        }
        return;
    } catch (Exception ex) {
        ex.printStackTrace();
    } catch (RuntimeException re) {
        re.printStackTrace();
    } finally {
        // 是否会输出?
        System.out.print("1");
    }
}
  1. start无IO异常不需要抛出
  2. RuntimeExcption不需要显式的throw
  3. catch的时候,要先从子类开始catch,代码中catch的顺序不对
  4. 没有关闭流
  5. return之前的finally block是会被执行的
14.BeanUtils类是深拷贝还是浅拷贝?

浅拷贝。如果拷贝User对象,修改之前User的Address变量,新的User中的Address变量也会发生改变。

public class Address {
    private String province;
    private String city;
    private String area;
    //省略构造函数和setter/getter
}

class User {
    private String name;
    private String password;
    private Address address;
    //省略构造函数和setter/getter
}
15.SimpleDateFormat是线程安全的吗?使用时应该注意什么?

不是,使用时应加锁或设置成局部变量,而不是直接使用static修饰。

假设线程1刚刚执行完calendar.setTime把时间设置成2018-11-11,还没等执行完,线程2又执行了calendar.setTime把时间改成了2018-12-12。这时候线程1继续往下执行,拿到的calendar.getTime得到的时间就是线程2改过之后的。

16.JDK新版本中都有哪些新特性?
  • JDK8中推出了Lambda表达式、Stream、Optional、新的日期API等
  • JDK9中推出了模块化
  • JDK10中推出了本地变量类型推断
  • JDK12中增加了switch表达式
  • JDK13中增加了text block
  • JDK14中增加了Records
  • JDK14中增加了instance模式匹配
  • JDK15中增加了封闭类
  • JDK17中扩展了switch模式匹配
  • JDK19中增加了协程
17.char能存储中文吗?

可以,char类型是用来表示一个16位的Unicode字符,它可以存储任何Unicode字符集中的字符,当然也包括中文字符。

18.为什么JDK 9中把String的char[]改成了byte[]?

当我们创建一个字符串时,如果它的所有字符都可以用单个字节表示,那么将会在内部使用字节数组来保存一半所需的空间,但是如果有一个字符需要超过8位来表示,Java将继续使用UTF-16与字符数组。

19.Arrays.sort是使用什么排序算法实现的?
  • 于比较常见的基本数据类型(如int、double、char等)的数组,就是采用JDK 1.7中引入的“双轴快速排序”;
  • 对于对象数组的排序,它支持两种排序方式,即归并排序和TimSort:
  • TimSort 是一种混合排序算法,结合了归并排序(Merge Sort)和插入排序(Insertion Sort)的特点。
上次更新: 5 个月前