面试题Java基础篇-常见面试题总结p3

Posted LL.LEBRON

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试题Java基础篇-常见面试题总结p3相关的知识,希望对你有一定的参考价值。

备战实习,会定期的总结常考的面试题,大家一起加油! 🎯

往期文章:

参考文章:

  • https://blog.csdn.net/qq_45966440/category_10889559.html
  • https://blog.csdn.net/weixin_43591980/category_10638797.html?spm=1001.2014.3001.5515
  • https://javaguide.cn/java/basis/java%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/
  • https://pdai.tech/

注意:

如果本文中有错误的地方,欢迎评论区指正!🍭

1.说一下try-catch-finally各个部分的作用?

  • try块: 用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally

  • catch块: 用于处理 try 捕获到的异常

  • finally 块: 无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行

👨‍💻面试官又问:finally是不是一定会被执行到?

不一定的。在在以下 3 种特殊情况下,finally 块不会被执行:

  1. tryfinally块中用了 System.exit(int)退出程序。但是,如果 System.exit(int) 在异常语句之后,finally 还是会被执行
  2. 程序所在的线程死亡
  3. 关闭 CPU

👨‍💻面试官继续追问:ftry-catch-finally中那个部分可以省略?

catch可以省略

try 只适合处理运行时异常,try+catch 适合处理运行时异常+普通异常

也就是说,如果你只用try去处理普通异常却不加以catch处理,编译是通不过的,因为编译器硬性规定,普通异常如果选择捕获,则必须用catch显示声明以便进一步处理。而运行时异常在编译时没有如此规定,所以catch可以省略

2.说说Error 和 Exception 的区别?

Error类和Exception类的父类都是Throwable类。主要区别如下︰

  • Error类

    表示JVM 无法处理的错误,我们没办法通过 catch 来进行捕获 。例如,Java 虚拟机运行错误虚拟机内存不够错误类定义错误等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止

  • Exception类

    程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可以分为 受检查异常(必须处理) 和 不受检查异常(可以不处理)

👨‍💻面试官追问:受检查异常和不受检查异常有什么不同?

  • 受检查异常

    Java 代码在编译过程中,如果受检查异常没有被 catch/throw 处理的话,就没办法通过编译 。

    除了RuntimeException及其子类以外,其他的Exception类及其子类都属于受检查异常 。常见的受检查异常有: IO 相关的异常、ClassNotFoundExceptionSQLException

  • 不受检查异常

    Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。

    RuntimeException 及其子类都统称为非受检查异常,例如:NullPointerExceptionNumberFormatException(字符串转换为数字)、ArrayIndexOutOfBoundsException(数组越界)、ClassCastException(类型转换错误)、ArithmeticException(算术错误)…

👨‍💻面试官继续追问:说一下你了解的常见异常类有哪些?

  • NullPointerException:当应用程序试图访问空对象时,则抛出该异常。
  • SQLException:提供关于数据库访问错误或其他错误信息的异常。
  • IndexOutOfBoundsException︰指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
  • FileNotFoundException︰当试图打开指定路径名表示的文件失败时,抛出此异常
  • IOException:当发生某种/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类。
  • ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出该异常
  • IllegalArgumentException:抛出的异常表明向方法传递了一个不合法或不正确的参数。

3.说说运行时异常和非运行时异常有什么区别?

  • 运行时异常

    都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

    运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

  • 非运行时异常

    也叫编译异常。是RuntimeException以外的异常,类型上都属于Exception类及其子类

    从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常

4.说一下throw 和 throws 的区别?

  • throw

    异常的抛出,在方法体内部,表示抛出异常,由方法体内部的语句处理;throw是具体向外抛出异常的动作,所以它抛出的是一个异常实例

    public static double method(int value) 
        if(value == 0) 
            throw new ArithmeticException("参数不能为0"); //抛出一个运行时异常
        
        return 5.0 / value;
    
    
  • throws

    异常的申明,在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理;表示出现异常的可能性,并不一定会发生这种异常

    public static void method() throws IOException, FileNotFoundException
        //something statements
    
    

5.知道try-with-resources吗?

如果你的资源实现了 AutoCloseable 接口,你可以使用这个语法。大多数的 Java 标准资源都继承了这个接口。当你在 try 子句中打开资源,资源会在 try 代码块执行后或异常处理后自动关闭。任何 catch 或 finally 块在声明的资源关闭后运行

Java 中类似于InputStreamOutputStreamScannerPrintWriter等的资源都需要我们调用close()方法来手动关闭,一般情况下我们都是通过try-catch-finally语句来实现这个需求,如下:

//读取文本文件的内容
Scanner scanner = null;
try 
    scanner = new Scanner(new File("D://read.txt"));
    while (scanner.hasNext()) 
        System.out.println(scanner.nextLine());
    
 catch (FileNotFoundException e) 
    e.printStackTrace();
 finally 
    if (scanner != null) 
        scanner.close();
    

使用 Java 7 之后的 try-with-resources 语句改造上面的代码:

try (Scanner scanner = new Scanner(new File("test.txt"))) 
    while (scanner.hasNext()) 
        System.out.println(scanner.nextLine());
    
 catch (FileNotFoundException fnfe) 
    fnfe.printStackTrace();

通过使用分号分隔,可以在try-with-resources块中声明多个资源:

try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
     BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) 
    int b;
    while ((b = bin.read()) != -1) 
        bout.write(b);
    

catch (IOException e) 
    e.printStackTrace();

6.说说你知道的Throwable 类常用方法?

  • public String getMessage():返回异常发生时的简要描述
  • public String toString():返回异常发生时的详细信息
  • public String getLocalizedMessage():返回异常对象的本地化信息。使用 Throwable 的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()返回的结果相同
  • public void printStackTrace():在控制台上打印 Throwable 对象封装的异常信息

栗子:

/**
 * @author xppll
 * @date 2021/11/30 09:08
 */
public class testThrowable 
    public static void main(String[] args) 
        try 
            int a = 10 / 0;
         catch (Exception e) 
            System.out.println("getMessage....."+e.getMessage());
            System.out.println("toString....."+e.toString());
            System.out.println("getLocalizedMessage....."+e.getLocalizedMessage());
            System.out.print("printStackTrace.....");
            e.printStackTrace();
        
    

输出:

getMessage...../ by zero
toString.....java.lang.ArithmeticException: / by zero
getLocalizedMessage...../ by zero
printStackTrace.....java.lang.ArithmeticException: / by zero
	at com.atguigu.mybatisplus.testThrowable.main(testThrowable.java:10)

7.说说什么是序列化?什么是反序列化?

如果我们需要持久化 Java 对象比如将 Java 对象保存在文件中,或者在网络传输 Java 对象,这些场景都需要用到序列化。

简单来说:

  • 序列化:将数据结构或对象转换成二进制字节流的过程
  • 反序列化:将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程

总的来说序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中

👨‍💻面试官追问:在Java序列化中如果有些字段不想进行序列化,怎么办?

对于不想进行序列化的变量,使用 transient 关键字修饰。它可以阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值也不会被持久化和恢复

例子:

创建实现Serializable接口的Person类:

/**
 * @author xppll
 * @date 2021/12/23 22:44
 */
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Person implements Serializable 
    private String name;
    private  transient  Integer age;

测试类:

/**
 * @author xppll
 * @date 2021/12/23 22:32
 */
public class test 
    public static void main(String[] args) 
        File file = new File("D://out.txt");
        //序列化对象
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream(file)
        )) 
            Person person = new Person("dad", 13);
            oos.writeObject(person);
         catch (IOException e) 
            e.printStackTrace();
        
    

结果:

可以看出没有age属性

👨‍💻面试官继续追问:关于transient的使用有什么需要注意的?

  • transient 只能修饰变量,不能修饰类和方法。
  • transient 修饰的变量,在反序列化后变量值将会被置成类型的默认值。例如,如果是修饰 int 类型,那么反序列后结果就是 0
  • static 变量因为不属于任何对象(Object),所以无论有没有 transient 关键字修饰,均不会被序列化

紧接上个测试案例,反序列化:

//反序列化
try (ObjectInputStream oos = new ObjectInputStream(
        new FileInputStream(file)
)) 
    Person res = (Person) oos.readObject();
    System.out.println(res
    );
 catch (IOException e) 
    e.printStackTrace();
 catch (ClassNotFoundException e) 
    e.printStackTrace();

控制台输出:

可以看出transient 修饰的变量,在反序列化后变量值将会被置成类型的默认值

8.说一下Java 中 IO 流分为几种?

  • 按照流的流向分,可以分为输入流输出流
  • 按照操作单元划分,可以划分为字节流字符流
  • 按照流的角色划分为节点流处理流

Java IO 流共涉及 40 多个类,这40 多个类都是从如下 4 个抽象类基类中派生出来的。

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

按操作方式分类结构图:

按操作对象分类结构图:

👨‍💻面试官追问:既然有了字节流,为什么还要有字符流??

字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好

9.请你说一说BIO、NIO、AIO 有什么区别?

在对比这三者的区别之前,先了解一下什么是同步/异步、阻塞/非阻塞:

  • 同步:一个任务的完成之前不能做其他操作,必须等待(相当于在打电话)
  • 异步:一个任务的完成之前,可以进行其他操作(相当于在聊QQ)
  • 阻塞:是相对于CPU来说的, 挂起当前线程,不能做其他操作只能等待
  • 非阻塞:无须挂起当前线程,也可以去执行其他操作
  • BIO:Block IO 同步阻塞,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。每当有一个客户端向服务器发起请求时,服务器都要启动一个线程,无论客户端是否响应,线程都必须一直等待。如图所示:

  • NIO:New IO 同步非阻塞,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。服务器用一个线程来处理多个请求,客户端发送的请求会注册到多路复用器(selector选择器)上,有I/O请求的客户端分配线程处理,如图:

  • AIO:Asynchronous IO 异步非阻塞,是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的 操作。

10.Java中的深拷贝和浅拷贝有了解过吗?

  • 浅拷贝

    对于基础数据类型:直接复制数据值;对于引用数据类型:只是复制了对象的引用地址,新旧对象指向同一个内存地址,修改其中一个对象的值,另一个对象的值随之改变。

  • 深拷贝

    对于基础数据类型:直接复制数据值;对于引用数据类型:开辟新的内存空间,在新的内存空间里复制一个一模一样的对象,新老对象不共享内存,修改其中一个对象的值,不会影响另一个对象。

下面举个详细的例子:

浅拷贝

/**
 * @author xppll
 * @date 2021/12/21 12:27
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address implements Cloneable
    private String name;

    @Override
    protected Object clone() throws CloneNotSupportedException 
        return super.clone();
    

/**
 * @author xppll
 * @date 2021/12/21 12:29
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person implements Cloneable
    private Address address;

    @Override
    protected Object clone() throws CloneNotSupportedException 
        return super.clone();
    

测试:

/**
 * @author xppll
 * @date 2021/12/21 12:30
 */
public class Test 
    public static void main(String[] args) throws CloneNotSupportedException 
        Person person1 = new Person(new Address("长沙"));
        Person person2 = (Person) person1.clone();
        System.out.println(person1.getAddress()==person2.getAddress());//true
    

从结果可以看出, person1 的克隆对象和 person1 使用的仍然是同一个 Address 对象。

深拷贝

这里我们简单对 Person 类的 clone() 方法进行修改,连带着要把 Person 对象内部的 Address 对象一起复制。

/**
 * @author xppll
 * @date 2021/12/21 12:29
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person implements Cloneable 
    private Address address;

    @Override
    protected Object clone() throws CloneNotSupportedException 
        Person person = (Person) super.clone();
        person.setAddress((Address) person.getAddress().clone());
        return person;
    

再次测试:

/**
 * @author xppll
 * @date 2021/12/21 12:30
 */
public class Test 
    public static void main(String[] args) throws CloneNotSupportedException 
        Person person1 = new Person(new Address("长沙"));
        Person person2 = (Person) person1.clone();
        System.out.println(person1.getAddress()==person2.getAddress());//false
    


最后喜欢的小伙伴,记得三连哦!😏🍭😘

以上是关于面试题Java基础篇-常见面试题总结p3的主要内容,如果未能解决你的问题,请参考以下文章

面试题Java基础篇-常见面试题总结p1

面试题Java基础篇-常见面试题总结p2

面试题Redis篇-常见面试题p1

面试题Redis篇-常见面试题p1

Java集合面试题看这篇就够了

Java集合面试题看这篇就够了