Java面试总结(十二)

cookie 和 session 是什么?都有什么优缺点和应用场景?

Cookie和Session都是Web开发中用于存储用户信息的机制,但是它们有不同的优缺点和应用场景。

Cookie是一种存储在用户浏览器中的小文件,用于存储用户的身份验证信息、偏好设置等数据。它的优点是易于实现、跨平台和跨浏览器兼容性好。但是,Cookie也有一些缺点,例如它的存储容量有限、容易被篡改、安全性较差等。Cookie适用于存储一些不敏感的数据,例如用户的偏好设置、购物车信息等。

Session是一种在服务器端存储用户信息的机制,它使用一个唯一的会话ID来标识每个用户,并将用户信息存储在服务器上。Session的优点是安全性高、存储容量大、能够存储敏感数据等。但是,Session也有一些缺点,例如它需要占用服务器资源、不易跨域等。Session适用于存储一些敏感的数据,例如用户的登录状态、权限信息等。

在应用场景方面,Cookie适用于存储一些不敏感的数据,例如用户的偏好设置、购物车信息等;而Session适用于存储一些敏感的数据,例如用户的登录状态、权限信息等。在实际应用中,通常会根据具体的需求来选择使用Cookie还是Session,或者两者结合使用。

Java 实现多线程的方式有哪些

  1. 继承 Thread 类:创建一个类继承 Thread 类,并重写 run() 方法,然后创建该类的对象,调用 start() 方法启动线程。

  2. 实现 Runnable 接口:创建一个类实现 Runnable 接口,并重写 run() 方法,然后创建该类的对象,将其传递给 Thread 类的构造方法中,创建 Thread 对象并调用 start() 方法启动线程。

  3. 实现 Callable 接口:创建一个类实现 Callable 接口,并重写 call() 方法,然后创建该类的对象,将其传递给 ExecutorService 的 submit() 方法中,执行任务并返回结果。

  4. 使用线程池:通过 Executors 工具类创建一个固定大小的线程池,然后将任务提交给线程池执行。

  5. 使用 FutureTask:创建一个类继承 FutureTask 类,并重写其 call() 方法,然后创建该类的对象,将其传递给 Thread 类的构造方法中,创建 Thread 对象并调用 start() 方法启动线程,最后使用 get() 方法获取执行结果。

  6. 使用 Lock 和 Condition:通过 Lock 和 Condition 接口实现线程间的协作,实现线程之间的通信和同步。

数据库索引有哪些注意点

  1. 索引的选择:选择合适的索引是非常重要的,因为一个不合适的索引会导致查询速度变慢,甚至会消耗更多的资源。通常情况下,我们应该选择那些经常被查询的列作为索引列。

  2. 索引的大小:索引的大小也是一个需要注意的问题。如果索引太大,会导致查询速度变慢,而如果索引太小,则可能会导致查询不准确。因此,我们需要根据实际情况选择合适的索引大小。

  3. 索引的更新:当我们对数据库进行修改操作时,索引也需要被更新。这个过程可能会消耗大量的资源,因此我们需要尽量减少索引的更新次数。

  4. 多列索引:如果我们需要查询多个列,可以考虑使用多列索引。这样可以提高查询速度,但也需要注意索引的大小和更新。

  5. 索引的重建:如果索引过于庞大或者已经过时,我们可能需要对其进行重建。这个过程需要谨慎处理,因为重建索引可能会导致数据库的性能下降。

  6. 索引的类型:不同类型的索引有不同的使用场景。例如,B树索引适用于范围查询,而哈希索引适用于等值查询。因此,我们需要根据实际情况选择合适的索引类型。

对springboot怎么理解

我个人的理解:SpringBoot 就是 Spring 的升级版,它解决了 Spring 很多的缺点,例如 Spring 需要自行配置大量的 xml 文件,而且 SpringBoot 提供嵌入式的 HTTP 服务器,如 Tomcat 和 Jetty ,可以更方便的开发和测试 Web 应用程序。

Exception 和 Error 有什么区别?

Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable 类有两个重要的子类 Exception(异常)和 Error(错误)。

Exception 和 Error 二者都是 Java 异常处理的重要子类,各自都包含大量子类。

  • Exception :程序本身可以处理的异常,可以通过 catch 来进行捕获,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。Exception 又可以分为运行时异常(RuntimeException, 又叫非受检查异常)和非运行时异常(又叫受检查异常) 。

  • Error :Error 属于程序无法处理的错误 ,不建议通过catch捕获。例如 Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等 。这些错误发生时,Java 虚拟机(JVM)一般会选择线程终止。

Error错误可以通过catch捕获,但是通常情况下不建议这样做。因为Error通常是一种非常严重的错误,它往往意味着虚拟机已经处于不稳定的状态,此时程序员很难通过代码进行恢复。如果在程序中捕获了Error,那么可能会掩盖错误的严重性,导致程序继续运行下去,而实际上程序已经处于一个不可预知的状态。因此,在Java程序中,通常不会对Error进行捕获和处理,而是让虚拟机自行处理。

Checked Exception 和 Unchecked Exception 有什么区别?

  • 受检查异常: 是Exception 中除 RuntimeException 及其子类之外的异常。 Java 编译器会检查受检查异常,Java 代码在编译过程中,如果受检查异常没有被 catch或者throws 关键字处理的话,就没办法通过编译。常见的受检查异常有: IO 相关的异常、ClassNotFoundException 、SQLException等。

  • 非受检查异常: 包括 RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。 Java 编译器不会检查运行时异常,Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译。例如:NullPointException(空指针)、NumberFormatException(字符串转换为数字)、IndexOutOfBoundsException(数组越界)、ClassCastException(类转换异常)、ArrayStoreException(数据存储异常,操作数组时类型不一致)等。

非受检查异常和受检查异常之间的区别:是否强制要求调用者必须处理此异常,如果强制要求调用者必须进行处理,那么就使用受检查异常,否则就选择非受检查异常。

Throwable 类常用方法有哪些?

  • String getMessage(): 返回异常发生时的简要描述

  • String toString(): 返回异常发生时的详细信息

  • String getLocalizedMessage(): 返回异常对象的本地化信息。使用 Throwable 的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()返回的结果相同

  • void printStackTrace(): 在控制台上打印 Throwable 对象封装的异常信息

try-catch-finally 如何使用?

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

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

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

如果try语句里有return,返回的是try语句块中变量值。 
详细执行过程如下:
	a.如果有返回值,就把返回值保存到局部变量中;
	b.执行jsr指令跳到finally语句里执行;
	c.执行完finally语句后,返回之前保存在局部变量表里的值。
	如果try,finally语句里均有return,忽略try的return,而使用finally的return.
public static void main(String[] args) {
    System.out.println(f(2));
}

public static int f(int value) {
    try {
        return value * value;
    } finally {
        if (value == 2) {
            return 0;
        }
    }
}

输出:

0

finally 中的代码一定会执行吗?

不一定的!在某些情况下,finally 中的代码不会被执行。

就比如说 finally 之前虚拟机被终止运行的话,finally 中的代码就不会被执行

try {
    System.out.println("Try to do something");
    throw new RuntimeException("RuntimeException");
} catch (Exception e) {
    System.out.println("Catch Exception -> " + e.getMessage());
    // 终止当前正在运行的Java虚拟机
    System.exit(1);
} finally {
    System.out.println("Finally");
}

Output:

Try to do something
Catch Exception -> RuntimeException

另外,在以下 2 种特殊情况下,finally 块的代码也不会被执行:

  1. 程序所在的线程死亡。
  2. 关闭 CPU。

为什么要抛出异常

异常是一种在程序中发现错误并使程序响应这些错误的机制,抛出异常可以将出现的异常信息从方法的处理过程中传递到其调用方,从而使代码更加容错和健壮。

以下是抛出异常的一些好处:

  1. 抛出异常可以明确和分离错误处理和正常代码路径。将异常处理与正常代码分离可以使程序更加清晰易懂,也有助于消除代码中的混淆。

  2. 抛出异常使错误处理更容易。利用异常机制,程序可以将错误转移到它知道如何处理的地方。如果在方法中遇到错误情况,它可以抛出异常,然后使用try-catch块在应用程序中正确处理这些异常。

  3. 抛出异常可以与日志记录相结合,帮助开发人员进行故障排除。程序员可以使用异常信息(包括异常类型、描述、堆栈跟踪等)来确定程序错误的根本原因,并找到解决它的方法。

总之,抛出异常可以使代码更加容错和健壮,帮助程序员快速识别和解决问题,提高代码质量和稳定性。

异常是程序发现错误并响应这些错误的一种机制。当程序中发生异常情况时,JVM都会抛出一个相应的异常对象。

在Java中,异常通常被封装在Exception类的子类中。Java中的异常分为两种类型:检查异常和非检查异常(也称为运行时异常)。

检查异常在代码中必须在方法签名中显式声明,并且在调用方法时必须显式定义处理这些异常的方式,否则编译将不通过。例如,FileNotFoundException是一个检查异常。

非检查异常(运行时异常)指的是程序员应该可以避免的异常,但是如果发生了,则在运行时才被检测到。这些异常通常是由程序员的错误或者假设条件无效而导致的。例如,NullPointerException是一个非检查异常。

当方法内部有可能发生异常时,程序员可以选择不处理该异常,而是将它“抛出(throw)”到该方法的调用者中。在Java中,可通过throw关键字完成此操作。调用者可以选择“捕获(catch)”该异常,并在适当的时候进行处理。

在Java中,方法可以使用throws子句显式声明方法可能会抛出哪些异常。在声明方法时,将异常类型添加到throws子句中,如果该方法可能抛出多个异常,则可以以逗号分隔它们。支付系统,你可以使用try-catch语句来捕获并处理异常,以避免它影响应用程序的正常运行。

异常的详细信息包括异常的类型、描述、异常发生时代码的位置以及堆栈跟踪(即调用堆栈),堆栈跟踪提供了有关异常发生的完整上下文信息,帮助我们在故障排除时更容易地定位和修复错误。

在编写程序时,抛出异常是一种有效的方式来标识代码中可能的错误情况,并减少应用程序崩溃,从而使代码更加健壮和可靠。

NoClassDefFoundError 和 ClassNotFoundException 区别?

NoClassDefFoundError 是一个 Error 类型的异常,是由 JVM 引起的,不应该尝试捕获这个异常。引起该异常的原因是 JVM 或 ClassLoader 尝试加载某类时在内存中找不到该类的定义,该动作发生在运行期间,即编译时该类存在,但是在运行时却找不到了,可能是编译后被删除了等原因导致。

ClassNotFoundException 是一个受检查异常,需要显式地使用 try-catch 对其进行捕获和处理,或在方法签名中用 throws 关键字进行声明。当使用 Class.forName, ClassLoader.loadClass 或 ClassLoader.findSystemClass 动态加载类到内存的时候,通过传入的类路径参数没有找到该类,就会抛出该异常;另一种抛出该异常的可能原因是某个类已经由一个类加载器加载至内存中,另一个加载器又尝试去加载它。

try-catch-finally 中哪个部分可以省略?

catch 可以省略。更为严格的说法其实是:try只适合处理运行时异常,try+catch适合处理运行时异常+普通异常。也就是说,如果你只用try去处理普通异常却不加以catch处理,编译是通不过的,因为编译器硬性规定,普通异常如果选择捕获,则必须用catch显示声明以便进一步处理。而运行时异常在编译时没有如此规定,所以catch可以省略,你加上catch编译器也觉得无可厚非。

理论上,编译器看任何代码都不顺眼,都觉得可能有潜在的问题,所以你即使对所有代码加上try,代码在运行期时也只不过是在正常运行的基础上加一层皮。但是你一旦对一段代码加上try,就等于显示地承诺编译器,对这段代码可能抛出的异常进行捕获而非向上抛出处理。如果是普通异常,编译器要求必须用catch捕获以便进一步处理;如果运行时异常,捕获然后丢弃并且+finally扫尾处理,或者加上catch捕获以便进一步处理。

至于加上finally,则是在不管有没捕获异常,都要进行的“扫尾”处理。

JVM 是如何处理异常的?

在一个方法中如果发生异常,这个方法会创建一个异常对象,并转交给 JVM,该异常对象包含异常名称,异常描述以及异常发生时应用程序的状态。创建异常对象并转交给 JVM 的过程称为抛出异常。可能有一系列的方法调用,最终才进入抛出异常的方法,这一系列方法调用的有序列表叫做调用栈。

JVM 会顺着调用栈去查找看是否有可以处理异常的代码,如果有,则调用异常处理代码。当 JVM 发现可以处理异常的代码时,会把发生的异常传递给它。如果 JVM 没有找到可以处理该异常的代码块,JVM 就会将该异常转交给默认的异常处理器(默认处理器为 JVM 的一部分),默认异常处理器打印出异常信息并终止应用程序。

异常传递

异常传递是指异常在方法之间传递的过程。当在Java程序中抛出异常时,JVM会在当前方法的调用堆栈中查找匹配的异常处理器来处理异常。如果在当前方法的调用堆栈中找不到任何匹配的异常处理器,则异常将继续向调用方传递,直到找到可以处理异常的异常处理器或将异常传递到程序的顶层,这时程序将终止并输出异常信息。

总结:

Java程序中,当发生异常时,会将异常的信息打包进一个异常对象中,并通过throw关键字抛出该异常对象。异常被抛出后,JVM会在当前方法中查找匹配的异常处理器进行处理,如果当前方法没有找到匹配的异常处理器,JVM会递归地查找当前方法的调用方法,并在调用方法中进行处理,直到找到匹配的异常处理器。如果 JVM 没有找到可以处理该异常的代码块,JVM 就会将该异常转交给默认的异常处理器(默认异常处理器为 JVM 的一部分),默认异常处理器打印出异常信息并终止应用程序。

异常使用有哪些需要注意的地方?

  • 不要把异常定义为静态变量,因为这样会导致异常栈信息错乱。

  • 每次手动抛出异常,我们都需要手动 new 一个异常对象抛出。

  • 抛出的异常信息一定要有意义。建议抛出更加具体的异常比如字符串转换为数字格式错误的时候应该抛出NumberFormatException而不是其父类IllegalArgumentException。

  • 使用日志打印异常之后就不要再抛出异常了(两者不要同时存在一段代码逻辑中)。

Java常见异常有哪些?

java.lang.IllegalAccessError:违法访问错误。当一个应用试图访问、修改某个类的域(Field)或者调用其方法,
但是又违反域或方法的可见性声明,则抛出该异常。

java.lang.InstantiationError:实例化错误。当一个应用试图通过Javanew操作符构造一个抽象类或者接口时抛出该异常。

java.lang.OutOfMemoryError:内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。

java.lang.StackOverflowError:堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出或者陷入死循环时抛出该错误。

java.lang.ClassCastException:类造型异常。假设有类ABA不是B的父类或子类),OA的实例,
那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。

java.lang.ClassNotFoundException:找不到类异常。当应用试图根据字符串形式的类名构造类,
而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。

java.lang.ArithmeticException:算术条件异常。譬如:整数除零等。

java.lang.ArrayIndexOutOfBoundsException:数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。

java.lang.IndexOutOfBoundsException:索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常。

java.lang.InstantiationException:实例化异常。当试图通过newInstance()方法创建某个类的实例,而该类是一个抽象类或接口时,
抛出该异常。

java.lang.NoSuchFieldException:属性不存在异常。当访问某个类的不存在的属性时抛出该异常。

java.lang.NoSuchMethodException:方法不存在异常。当访问某个类的不存在的方法时抛出该异常。

java.lang.NullPointerException:空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。
譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。

java.lang.NumberFormatException:数字格式异常。当试图将一个String转换为指定的数字类型,
而该字符串确不满足数字类型要求的格式时,抛出该异常。

java.lang.StringIndexOutOfBoundsException:字符串索引越界异常。当使用索引值访问某个字符串中的字符,
而该索引值小于0或大于等于序列大小时,抛出该异常。
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路上阡陌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值