首页 > 编程语言 >Java面试笔试题大汇总(最全+详细答案)

Java面试笔试题大汇总(最全+详细答案)

时间:2025-01-10 16:33:34浏览次数:3  
标签:Java String 对象 方法 最全 题大 字符串 异常

1. 抽象类和接口的对比

从设计层面来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。

相同点

① 接口和抽象类都不能实例化

② 都位于继承的顶端,用于被其他类实现或继承

③ 都包含抽象方法,其子类都必须重写这些抽象方法

不同点

注:Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间的差异。现在,我们可以为接口提供默认实现的方法了,并且不用强制子类来实现它。


2. 成员变量与局部变量的区别有哪些


3. 重载(Overload)和重写(Override)的区别?

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。

重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分

重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写。


4. == 和 equals 的区别是什么

== : 它的作用是判断两个对象的内存地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)

equals() : 它的作用也是判断两个对象是否相等。有两种使用情况:

情况1:类没有覆盖 equals() 方法,等价于通过“==”比较这两个对象。

情况2:类覆盖了 equals() 方法。一般我们都覆盖 equals() 方法来判断两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。


篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记及答案【点击此处即可】免费获取

5. hashCode 与 equals

hashCode()介绍

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int类型的整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object类中,这就意味着Java中的任何类都包含有hashCode()函数。

散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

为什么要有 hashCode

我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:

当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相同的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。

先进行 hashcode 比较,后进行 equals 方法比较的目的:可以大大减少了 equals 方法比较的次数,相应就大大提高了执行速度。

hashCode()与equals()的相关规定

如果两个对象相等,则hashcode一定也是相同的

两个对象相等,对两个对象分别调用equals方法都返回true

两个对象有相同的hashcode值,它们不一定是相等的

因此,当重写equals方法后有必要将hashCode方法也重写,这样做才能保证不违背hashCode方法中“相同对象必须有相同哈希值”的约定。


6. 值传递和引用传递有什么区别

值传递:调用函数时将实际参数复制一份传递到函数中,函数内部对参数内部进行修改不会影响到实际参数,即创建副本,不会影响原生对象

引用传递 方法接收的是实际参数所引用的地址,不会创建副本,对形参的修改将影响到实参,即不创建副本,会影响原生对象


四、异常

1. 什么是异常?请描述一下Java异常架构

 Java异常是Java提供的一种识别及响应错误的一致性机制。异常能清晰的回答what, where, why这3个问题:

异常类型回答了“什么”被抛出,

异常堆栈跟踪回答了“在哪”抛出,

异常信息回答了“为什么”会抛出。


2. Error 和 Exception 区别是什么?

Error:表示系统级的错误和程序不必处理的异常,例如系统崩溃、内存溢出、jvm错误

Exception:表示需要捕捉或者需要程序进行处理的异常,


3. 什么是运行时异常,编译时异常?什么是受检异常与非受检异常

运行时异常(非受检异常):RuntimeException 类及其子类,Java 编译器不会检查它,此类异常一般是由程序逻辑错误引起的,需要通过修改代码来进行避免

编译时异常(受检异常):Exception 中除 RuntimeException 及其子类之外的异常,Java 编译器会检查它,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译



4. JVM 是如何处理异常的?

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

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


5. 从性能角度来审视一下 Java 的异常处理机制

try-catch 代码段会产生额外的性能开销,或者换个角度说,它往往会影响 JVM 对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的 try 包住整段的代码;

利用异常控制代码流程,也不是一个好主意,远比我们通常意义上的条件语句(if/else、switch)要低效;

Java 每实例化一个 Exception,都会对当时的堆栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略了。


6. throw 和 throws 的区别是什么?

throw:运用于方法内部,用于给调用者返回一个异常对象,和renturn一样结束当前方法

throws:运用于方法声明之上,用于表示当前方法不处理异常,而是提示该方法的调用者处理异常


7. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

其实return与finally并没有明显的谁强谁弱。在执行时,是return语句先把返回值写入但内存中,然后停下来等待finally语句块执行完,return再执行后面的一段

例子:如果fun1的finally加上return输出就是20,因为重新放到内存里,而fun2本身是操作内存,因为s是引用类型


  1. public int fun1() {

  2. int i = 10;

  3. try { return i; } catch (Exception e) { return i; } finally { i = 20;  }

  4. }  // 10

  5. public StringBuilder fun2() {

  6.  StringBuilder s = new StringBuilder("1");

  7.           try {

  8. s.append("2"); return s; }

  9. catch (Exception e) {

  10. return s;

  11. } finally {

  12. s.append("3");

  13. }

  14. }  // 123

8. Java常见异常有哪些

① Error

          java.lang.OutOfMemoryError(内存不足错误)

          java.lang.StackOverflowError(堆栈溢出错误)

② Exception(编译异常)

          NoSuchMethodException(方法未找到异常)

          IOException(输入输出异常)

          EOFException(文件已结束异常)

          FileNotFoundException(文件未找到异常)

          NumberFormatException(字符串转换为数字异常)

          SQLException(操作数据库异常)

③ RuntimeException(运行时异常)

         ConcurrentModificationException(并发修改异常)

          NullPointerException(空指针异常)

          ClassCastException(类转换异常)

          IndexOutOfBoundsException(索引越界异常)

          ClassNotFoundException(类文件未找到异常)

          ArithmeticException(数学计算异常)


9. 说几个Java异常处理最佳实践
  1. 不要忽略异常:在Java中,忽略异常是一种很常见的错误。它可能导致程序崩溃、数据丢失等问题。所以在异常处理中一定不要忽略异常,应该对异常进行适当的处理。

  2. 使用try-catch-finally块:在处理异常时,应该使用try-catch-finally块。try块中包含可能会抛出异常的代码,catch块中包含处理异常的代码,finally块中包含无论是否发生异常都需要执行的代码。这种方式可以有效地捕获异常并进行处理。

  3. 使用多个catch块:在使用try-catch块时,应该使用多个catch块来捕获不同类型的异常。这可以使异常处理更加细粒度化,从而更加有效地处理不同类型的异常。

  4. 不要在finally块中抛出异常:在finally块中抛出异常是一种很常见的错误。如果在finally块中抛出异常,它可能会覆盖在try块或catch块中抛出的异常,从而使问题更加难以排查。所以在finally块中最好只执行一些清理工作,而不是抛出异常。

  5. 不要捕获不必要的异常:有些异常是Java中的运行时异常,它们在运行时可能会发生,但通常不需要捕获。捕获不必要的异常会增加代码的复杂性,并可能导致性能下降。

  6. 使用自定义异常:在Java中,可以使用自定义异常来表示特定的错误或异常情况。这可以使异常处理更加细粒度化,并使代码更易于维护和调试。

  7. 记录异常信息:在捕获异常时,应该记录异常信息,包括异常类型、异常消息和堆栈跟踪信息。这可以帮助开发人员更好地理解问题所在,并更快地排查问题。


10. NoClassDefFoundError 和 ClassNotFoundException 有什么区别?

NoClassDefFoundError:是一个错误(Error),JVM或者ClassLoader实例尝试加载类的时候却找不到类的定义。要查找的类在编译的时候是存在的,运行的时候却找不到了。这个时候就会导致NoClassDefFoundError。

ClassNOtFoundException:是一个异常,Java支持使用反射方式在运行时动态加载类,例如使用Class.forName方法来动态地加载类时,可以将类名作为参数传递给上述方法从而将指定类加载到JVM内存中,如果这个类在类路径中没有被找到,那么此时就会在运行时抛出ClassNotFoundException异常


11. OOM你遇到过哪些情况,SOF你遇到过哪些情况

OOM:

1,OutOfMemoryError异常

2,虚拟机栈和本地方法栈溢出

3,运行时常量池溢出

4,方法区溢出

SOF(堆栈溢出StackOverflow):

StackOverflowError 的定义:当应用程序递归太深而发生堆栈溢出时


 篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记及答案【点击此处即可】免费获取

五、IO流

1. java 中 IO 流分为几种?

按照流的流向分:可以分为输入流输出流

按照操作单元划分:可以分为字节流字符流

按照流的角色划分:可以分为节点流和处理流。

Java IO流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java IO流的40多个类大部分都是从如下4个抽象类基类中派生出来的。

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

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


2. Java中字符流与字节流的区别?

Java中的字节流处理的最基本单位为单个字节,它通常用来处理二进制数据

 Java中的字符流处理的最基本的单元是Unicode码元(大小2字节),它通常用来处理文本数据


3. BIO,NIO,AIO 有什么区别?

BIO、NIO 和 AIO 都是 Java 中用于实现网络编程的技术,它们有以下区别:

  1. BIO(Blocking I/O)同步阻塞 I/O,即传统的 I/O 模型,使用阻塞式的方法处理数据流。BIO 的特点是模型简单、编程方便,但并发处理能力较弱,适用于连接数目比较小且固定的架构,例如,实现简单的服务器。

  2. NIO(Non-blocking I/O)同步非阻塞 I/O,即新的 I/O 模型,使用非阻塞式的方法处理数据流。NIO 的特点是支持高并发,适用于连接数目多且连接比较短的架构,例如,实现高性能 Web 服务器等。

  3. AIO(Asynchronous I/O)异步非阻塞 I/O,即基于事件和回调机制实现的 I/O 模型。AIO 的特点是能够处理更多的并发请求,适用于连接数目多且连接比较长的架构,例如,实现高并发的网络应用程序。


4. BIO、NIO、AIO 实现原理

BIO(Blocking I/O)实现原理:BIO 使用阻塞式 I/O 处理数据,采用同步阻塞方式,即应用程序的线程在读取或写入数据时,如果数据还没有准备好,那么线程会被阻塞,直到数据准备好并读取或写入完成。

NIO(Non-blocking I/O)实现原理:NIO 使用非阻塞式 I/O 处理数据,采用同步非阻塞方式,即应用程序的线程可以继续执行其他任务,而不是等待数据的读取或写入。当数据准备好后,线程会得到通知,可以读取或写入数据。

NIO 实现的关键是选择器(Selector)和通道(Channel)的概念。选择器可以同时监控多个通道的状态,当一个通道的状态发生变化时,选择器会得到通知,线程可以处理该通道的数据。

AIO(Asynchronous I/O)实现原理:AIO 采用异步非阻塞方式,即应用程序的线程不需要等待数据的读取或写入,而是通过回调机制在数据读取或写入完成后得到通知。AIO 实现的关键是异步通道(Asynchronous Channel)和 CompletionHandler 回调函数。

异步通道可以在数据读取或写入完成后向操作系统发出通知,当操作系统完成数据读取或写入后,会调用注册的 CompletionHandler 回调函数,应用程序可以在回调函数中处理读取或写入的数据。

总之,BIO、NIO、AIO 三种技术实现原理不同,分别采用同步阻塞、同步非阻塞和异步非阻塞方式处理数据。选择合适的技术取决于应用程序的特点和需求。


六、反射

1. 什么是反射机制?

JAVA反射机制是在程序运行过程中,对于任意一个类或对象,都能够知道这个类或对象的所有属性和方法,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

静态编译和动态编译

静态编译:在编译时确定类型,绑定对象

动态编译:在运行时确定类型,绑定对象


2. 反射机制优缺点

优点 :运行期类型的判断,动态加载类,提高代码的灵活性。

缺点:性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。


3. 反射为什么慢

① 反射调用过程中会产生大量的临时对象,这些对象会占用内存,可能会导致频繁 gc,从而影响性能。

② 反射调用方法时会从方法数组中遍历查找,并且检查可见性等操作会比较耗时。

③ 反射在达到一定次数时,会动态编写字节码并加载到内存中,这个字节码没有经过编译器优化,也不能享受 JIT 优化

④ 反射一般会涉及自动装箱/拆箱和类型转换,都会带来一定的资源开销。


4. 反射机制的应用场景有哪些?

反射机制可以使得Java程序在运行时动态地获取类的信息并对其进行操作,它的应用场景非常广泛,以下是一些常见的应用场景:

  1. 动态加载类和调用方法:反射机制可以使得程序在运行时动态地加载和使用类,这样可以提高程序的灵活性和可扩展性。例如,可以通过Class.forName()方法动态加载一个类,并使用getMethod()方法获取类中的方法,然后使用invoke()方法调用方法。

  2. 配置文件的读取:反射机制可以根据配置文件中的类名、方法名等信息动态地加载和使用类,并调用其中的方法。

  3. 单元测试框架:JUnit等单元测试框架就是使用反射机制来自动调用被测试代码中的测试方法,并根据测试结果输出测试报告。

  4. Java Bean 的属性获取和设置:反射机制可以根据 Java Bean 中的属性名动态地获取和设置属性的值,这在一些框架中非常常见,如Spring等。

  5. AOP编程:反射机制可以用来实现AOP编程,通过动态代理的方式实现在不修改源代码的情况下增强程序的功能,例如实现日志记录、性能统计等。

总的来说,反射机制在Java中有很广泛的应用场景,它可以使得程序更加灵活、可扩展和可维护。但是,由于反射机制涉及到很多底层细节,使用不当可能会影响程序的性能和稳定性,因此需要谨慎使用。


七、常用API

1. 字符型常量和字符串常量的区别

形式上:字符常量是单引号引起的一个字符,字符串常量是双引号引起的若干个字符

含义上:字符常量相当于一个整形值(ASCII值),可以参加表达式运算,字符串常量代表一个地址值(该字符串在内存中存放位置)

占用内存大小:字符常量只占两个字节,字符串常量占若干个字节


2. String的创建机理是什么?什么是字符串常量池?

创建机理:由于String在Java世界中使用过于频繁,为了提高内存的使用率,避免开辟多块空间存储相同的字符串,引入了字符串常量池(字符串常量池位于堆内存中)。

其运行机制是:在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。


3. String 是最基本的数据类型吗

不是。Java 中的基本数据类型只有 8 个,除了基本类型(primitive type),剩下的都是引用类型(referencetype)

基本数据类型中用来描述文本数据的是 char,但是它只能表示单个字符,如果要描述一段文本,就需要使用 char 类型数组,但是使用数组过于麻烦,所以就有了 String,String 底层就是一个 char 类型的数组,只是使用的时候开发者不需要直接操作底层数组,使用更加简便


4. String s = new String(“abc”);创建了几个字符串对象

当JVM遇到上述代码时,会先检索常量池中是否存在“abc”,如果不存在“abc”这个字符串,则会先在常量池中创建这个字符串。然后再执行new操作,在堆内存中创建一个String对象,对象的引用赋值给s。此过程创建了2个对象。

当然,如果检索常量池时发现已经存在了对应的字符串,那么只会在堆内创建一个新的String对象,此过程只创建了1个对象。


  1. String str1 = "hello"; //str1指向静态区

  2. String str2 = new String("hello");  //str2指向堆上的对象

  3. String str3 = "hello";

  4. String str4 = new String("hello");

  5. System.out.println(str1.equals(str2)); //true

  6. System.out.println(str2.equals(str4)); //true

  7. System.out.println(str1 == str3); //true

  8. System.out.println(str1 == str2); //false

  9. System.out.println(str2 == str4); //false

  10. System.out.println(str2 == "hello"); //false

  11. str2 = str1;

  12. System.out.println(str2 == "hello"); //true


5. String为什么设计为final,一个类修饰为final有什么好处

final修饰的String类,代表了String类的不可被继承,final修饰的char[]代表了被存储的数据不可更改。String类一旦在常量池(节省资源,提高效率,因为如果已经存在这个常量便不会再创建,直接拿来用)被创建,是无法修改的,即便你在后面拼接一些其他字符,也会把新生成的字符串存到另外一个地址。但是,虽然final代表了不可变,但仅仅是引用地址不可变,并不代表了数组本身不会变

线程安全,多线程下对资源进行写操作是有风险的,不可变对象不能被写,所以线程安全

因为字符串是不可变的,所以在它创建的时候HashCode就被缓存了,不需要重新计算,这就是HashMap中的键往往都使用字符串的原因之一


6. 在使用 HashMap 的时候,用 String 做 key 有什么好处?

HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快


7. String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的

 String 类型是不可变的,一旦创建就不能被修改,如果需要对其内容进行修改,只能创建一个新的 String 对象。而 StringBuffer 和 StringBuilder 则是可变的,可以修改其内容,而不会创建新的对象。

 StringBuffer 是线程安全的,因此在多线程环境下使用比较安全,但是其性能较低。StringBuilder 则是非线程安全的但是其性能比 StringBuffer 更高

③ 在字符串操作较少的情况下,使用 String 类型即可如果需要频繁修改字符串内容,而又不需要考虑线程安全问题,可以使用 StringBuilder 类型如果需要考虑线程安全问题,可以使用 StringBuffer 类型

标签:Java,String,对象,方法,最全,题大,字符串,异常
From: https://blog.csdn.net/2401_89221867/article/details/145059970

相关文章

  • 20、javase-API.容器
    为了在程序中可以保存数目不确定的对象,Java提供了一系列特殊的类容器。位于java.util包中,使用时必须导包。容器按照其存储结构可以分为两大类单列集合CollectionList:元素有序、可重复ArrayListLinkedListSet:元素无序,不可重复HashSetTreeSet双列集......
  • Java生成Word文档之 XDocReport 和 Poi-tl
    近期参与的多个项目中,均涉及根据预定义模板生成Word文档以供前端下载的需求。以往,我们通常采用将Word文档转换为XML格式,并通过代码赋值变量的方式来实现这一功能。尽管此方法在技术层面可行,但当面对篇幅较长且包含大量变量的文档时,其弊端便显露无遗:代码冗长繁杂,模板维护困难,不利......
  • JavaScript的DOM讲解
     一、DOM基础概念 (1)DOM定义:文档对象模型(DocumentObjectModel)        作为一系列极具实用价值的编程接口,赋予了开发者改变网页内容、调整页面结构以及修饰样式的能力。在DOM的体系架构里,网页文档由document精准指代,页面元素对应着element,而像标签、属性、文本......
  • java poi 模板导出 套用表格格式
    模板文件格式如下 生成数据后样式如下 poi3.17 excel2007已上xlsx 直接上代码。拿走不谢!1publicstaticXSSFWorkbookreadTemplate(StringfilePath)throwsIOException{2try(FileInputStreamfis=newFileInputStream(filePath)){3......
  • 深入解析:利用Java爬虫挖掘淘宝商品评论的宝藏
    在当今数字化时代,消费者的声音成为了品牌和商家决策的关键因素。淘宝作为国内领先的电商平台,其商品评论数据蕴含着巨大的商业价值。本文将带你深入了解如何利用Java爬虫技术,通过淘宝商品评论API接口(item_review),高效地获取并分析这些宝贵的用户反馈,为你的电商运营、市场调研或数据......
  • JavaScript系列(16)--原型继承
    JavaScript原型继承......
  • JAVA数组
    1、数组定义:是一种容器,可以用来存储同种数据类型的多个值。数据容器在存储容器的时候,需要结合隐式转换考虑。建议:容器的类型和存储的数据类型保持一致。2、数组格式:一、数据类型[]数组名二、数据类型数组名[]3、数组初始化:初始化:就是在内存中,为数组容器开辟容器,......
  • JAVA方法
    1、什么是方法?方式(method)是程序中最小的执行单元。2、方法的用处和好处?用处:重复的代码、具有独立功能的代码可以抽取到方法中。好处:可以提高代码的复用性;可以提高代码的可维护性3、方法的格式方法定义:把一些代码打包在一起,该过程称为方法定义方法调用:方法定义后并不......
  • Java实现生成永不重复的数字方案详解
    哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者......
  • python+django/flask的惠安租房管理平台java+nodejs+php-计算机毕业设计
    目录技术栈和环境说明具体实现截图预期达到的目标系统设计详细视频演示技术路线解决的思路性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示研究方法感恩大学老师和同学源码获取技术栈和环境说明本系统以Python开发语言......