您的位置:首页 > 健康 > 养生 > 【八股文】Java基础篇

【八股文】Java基础篇

2024/12/23 10:06:12 来源:https://blog.csdn.net/qq_45249273/article/details/140901539  浏览:    关键词:【八股文】Java基础篇

1. == 和 equals的区别是什么?

  • == 判断两个变量或者实例是否都指向同一内存空间的值(不仅值相同,地址也要相同)
  • equals是判断两个变量执行的内存空间的值是否相同(值相同,地址可以不同),所以一般class要做equals判断时,要重写equals方法。重写equals方法就要重写hashCode方法,例如下面这个例子,当str,name和str都相同时,才会相同
@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;NN nn = (NN) o;return val == nn.val && Objects.equals(name, nn.name) && Objects.equals(str, nn.str);}@Overridepublic int hashCode() {return Objects.hash(name, val, str);}

2.两个对象的hashCode()相同,则equals()也一定为true吗?

不一定,因为我们通过hash散列出来的值会产生冲突,也就是不同的值,散列出来相同的值。反之,如果equals为true,则两个对象的hashCode一定相同

3.final在Java中有什么作用?

final 是一个修饰符,可以用于类、方法或变量。当final修饰变量时,如果这个变量是基础类型,那么该变量不能被修改,如果是引用类型,那么该变量不能指向另外一个对象,但内部的状态可以修改;当final修饰类时(例如String类),这个类不能被继承;当final修饰方法时,该方法不能被子类重写。追问

  • 3.1 final,finally和finalize有什么区别
    • final:上面回答
    • finally:一般与异常相关,用于try-catch-finally语句块中。不管有没有发生异常,在finally代码块中用于释放资源,因为finally块中的代码一定会被执行。
    • finalize:
      • finalize是Object方法,因此,所有类都隐式继承了这个方法
      • 它是垃圾回收机制的一部分,当垃圾回收器决定回收一个对象之前,会调用该对象的finalize方法。
      • 我们可以覆盖finalize方法来执行一些类似于释放系统资源操作,但Java 9开始该方法就不被推荐使用了,因为它的执行时间和确定性无法保证。
      • 现在Java更推荐其他资源管理机制,如try-with-resources语句或显式的资源管理策略。
    • 总结:final关注的是不变性,而finally关注的是确保代码执行,而finalize关注的是对象被销毁前的清理工作,但现在都使用try-with-resources语句。使用技巧如下:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;public class MultipleResourcesExample {public static void main(String[] args) {String filePath = "data.txt";String url = "jdbc:mysql://localhost:3306/mydb";String user = "root";String password = "password";try (BufferedReader reader = new BufferedReader(new FileReader(filePath));Connection conn = DriverManager.getConnection(url, user, password);Statement stmt = conn.createStatement()) {String line;while ((line = reader.readLine()) != null) {// 假设每行包含一条SQL命令stmt.execute(line);}} catch (IOException | SQLException e) {System.err.println("Error processing resources: " + e.getMessage());}}
}

4.面向对象的三大特性

  • 封装(提高代码安全性低):将对象的属性和方法封装到一起,只暴露有限的接口供外部访问。这样防止外部程序随意修改对象的属性和调用其方法
  • 继承(提高代码复用性):新类可以继承现有的类,允许资料复用父类的代码,同时还可以添加和覆盖一些行为。
  • 多态(提高代码灵活性和可扩展性):多态是指同一个接口可以有多种不同的实现,或者一个类实例可以拥有多个类型。多态可以通过方法重载和重写来实现。

5.多态的实现原理

  • 多态的实现原理是动态绑定,即在运行时才把方法调用和方法实现关联起来。
    • 一种是编译时多态,被称为静态分派,比如方法的重载
    • 一种是运行时多态,被称为动态分派,比如方法的重写和接口的实现
  • 多态的实现:多态的实现过程,就是方法调用动态分派的过程,如果子类覆盖了父类的方法,则在多态调用中,动态绑定过程首先确定实际类型是子类,从而先搜索到子类中的方法。这个过程便是方法覆盖的本质。

6.静态变量和成员变量的区别

特性成员变量静态变量
存储位置存储在堆内存的对象实例中存储在方法区(如元空间)
生存周期与对象的生命周期相同与应用程序的生命周期相同
实例数量每个对象实例有一份副本所有对象实例共享同一份
访问方式必须通过对象实例访问可以通过类名直接访问,也可以通过对象实例访问
作用域局限于单个对象实例对所有对象实例可见
初始化每次创建对象时初始化类加载时初始化一次

7.是否可以从一个静态方法内部发出对非静态方法调用

不可以直接从静态方法内部调用非静态方法。这是因为静态方法属于类级别,而非静态方法属于对象实例级别。静态方法在没有创建类的任何实例下就可以被调用,而调用非静态方法则需要先创建类的实例。然而,我们可以在静态方法内部间接调用非静态方法,通过创建类的实例并使用该实例来调用非静态方法。静态方法内部也不能直接使用成员变量,也需要创建类的实例才行。

8.深拷贝和浅拷贝区别是什么

  • 浅拷贝:创建一个新的对象,复制基本类型字段,引用类型字段仅复制引用,导致原始对象和拷贝对象共享相同的引用类型数据
  • 深拷贝:递归地复制所有字段,包括引用类型字段所指向的对象,确保原始对象和拷贝对象完全独立。
  • (追问)深拷贝有哪些实现方式
    • 序列化:将对象转换为字节流,然后再从字节流中重构出一个新对象。这种方式适用于实现了Serializable接口的引用类型字段也需要支持深拷贝
    • 克隆:利用Cloneable接口和clone()方法实现对象的拷贝。需要注意的是,clone()方法必须在子类中重写,并且引用类型字段也需要支持深拷贝
    • 手动实现,在类中手动编写代码,递归地复制所有引用类型字段所指向的对象。

9.HashMap相关考点

HashMap相关考点

10.Java中的初始化

先初始化静态代码块和静态变量,因为静态代码块和静态变量是在该类被第一次调用时就初始化了,以后不在初始化,而成员变量和构造方法这些只有对象被实例化过后才被初始化。如果有父类则执行顺序是这样的父类静态变量和静态代码块-》子类静态变量和非静态代码块-》父类非静态变量和静态代码块-》父类构造器-》子类非静态变量非静态代码块-》子类构造器

11.String、StringBuilder、StringBuffer的区别

特性StringStringBuilderStringBuffer
可变性不可变可变可变
线程安全性内置线程安全(由于不可变性)非线程安全线程安全
性能修改操作效率低(每次修改创建新对象)修改效率高(无需创建新对象)修改效率较高(因为加了锁)
内部存储私有且最终的字符数组可修改的字符数组同StringBuilder
典型使用场景常量字符串或不需要修改的字符串单线程下频繁修改的字符串构建多线程下频繁修改的字符串构建

12.什么是反射

  • 反射允许运行时检查和修改程序的行为。通过反射,程序可以在运行时获取类、接口、方法和字段的信息,并可以动态地创建和操作对象。
  • 反射功能(优点)
    • 获取到类信息(类中所有方法,类名,包名等等)
    • 可以通过反射实例化对象
    • 可以调用对象的任意方法,包括私有的
    • 可以读取和修改对象的任意字段
    • 能够获取和调用类的构造器。
  • 反射的缺点
    • 性能开销大:反射操作通常比直接Java代码慢得多,因为涉及到类信息的查询和解析方法调用
    • 安全性低:反射可以访问和修改私有成员,可能破坏类的封装性。
    • 代码可读性低:使用反射的代码比较难以阅读和调试。
  • 反射的场景
    • 动态加载和实例化类:插件架构中
    • 动态配置和调用方法:在配置驱动的框架中
    • 自动化测试:模拟对象和调用私有方法
    • 实现框架和库:序列化、注解和AOP等。

13.重载和重写的区别

  • 重写是在父类和子类直接实现的,而重载是在同一个类中实现的
  • 重写的形参和返回值要一样,而重载可以不一样
  • 都是多态的特性
  • 重载发生在编译时,由编译器根据传递给方法的参数类型和数量来决定调用哪个方法,而重写发生在运行时,当调用方法时,JVM会检查对象的实际类型,并调用相应的重写方法,这就是动态绑定。
    (追问)为什么不能根据不同返回值类型来区别重载
  • 编译时解析:Java编译器在编译阶段就需要确定调用哪个方法。如果允许根据返回类型来区分重载,那么编译器就无法在编译时确定正确的方法,因为此时可能还不知道实际的返回类型,这会导致编译失败。
  • 类型系统:Java是一种静态类型语言,这意味着在编译时就需要确定所有类型信息。如果方法的调用依赖于运行时的返回类型来决定调用哪个方法,这将违背Java的静态类型规则。

14.抽象类和接口的区别

特性抽象类接口
实例化不能直接实例化,但可以有非抽象的子类实例化不能实例化,也没有子类的概念,类通过实现接口来使用它
抽象方法可以有抽象方法(没有方法体),也可以有具体方法默认所有方法都是抽象的,除非使用default或static修饰
多重继承不支持支持多重继承的思想,一个类实现多个接口
实例变量可以有实例变量,用于保存状态不能有实例变量,可以有静态常量
构造函数可以有没有,因此不能被实例化
访问修饰方法和变量都可以有任意的访问修饰符方法默认是public的,常量默认是public static final的
使用场景用于提供共享行为和状态,以及强制子类实现特定方法用于定义行为规范,多个不相关的类可以实现同一个接口

15.Error和Exception的区别

特性ErrorException
类型表示严重的系统级问题或程序无法处理的错误表示程序可以尝试处理的问题或异常情况
处理一般不应被捕获或处理,因为程序必须终止应该被捕获并处理,以避免程序崩溃并提供恢复的可能性
实例StackOverflowError、OutOfMemoryErrorNullPointerException、IOException
继承体系ThrowableThrowable
抛出异常在资源耗尽或JVM遇到无法恢复的错误时抛出在程序逻辑错误或运行时资源不可用时抛出
可捕获性通常不可捕获可以通过try-catch捕获
使用场景用于标识系统错误,如JVM内部错误或资源耗尽用于处理程序级别的异常,如空指针异常等

16.为什么Java中只有值传递

值传递模型增加了代码的安全性,因为方法不能意外地修改外部变量的状态。这对于维护多线程和并发程序尤其重要,因为它减少了共享状态的副作用。

17.ArrayList、Vector和LinkedList的区别

特性ArrayListVectorLinkedList
底层数据结构基于动态数组基于动态数组基于双向链表
元素访问使用索引访问 O(1)也是O(1)O(n),需要变量链表指定位置
元素插入或删除都是O(n),可能会移动元素也只是O(n)都是O(1),因为是链起的
线程安全性非线程安全线程安全非线程安全,但提供 addFirst和addLast等线程安全的栈和队列操作
扩容策略当容量不足时,按照1.5倍扩容同ArrayList无需扩容,动态创建
元素顺序保持插入顺序,支持随机访问同ArrayList保持插入顺序,但是不能随机访问
内存占用基于数组,所以相对紧凑同ArrayList每个元素需要额外的内存用于存储前后节点的饮用,pre和next
常见使用场景需要随机访问,插入和删除较少的场景需要多线程环境中使用集合的场景需要频繁插入和删除元素的场景

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com