Java SE八股整理.md
# Java SE八股整理 ## Java 核心特性 - 面向对象:支持封装、继承、多态三大特性,以对象为核心组织程序结构 - 平台无关性:基于 JVM 屏蔽底层差异,将源代码编译为字节码后可在任意安装JVM的平台上运行 - 内存自动管理:内置垃圾回收机制(GC),无需像C语言手动调用 malloc/free 释放内存,降低了内存泄露的风险 - …… ## JVM、JRE、JDK > [JAVAGUID-java基础](https://javaguide.cn/java/basis/java-basic-questions-01.html#java-%E8%AF%AD%E8%A8%80%E6%9C%89%E5%93%AA%E4%BA%9B%E7%89%B9%E7%82%B9) JVM:Java 虚拟机(Java Virtual Machine, JVM)是运行 Java 字节码的虚拟机。JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在。 JRE:Java Runtime Environment,JRE 是运行已编译 Java 程序所需的环境,主要包含以下两个部分: 1. **JVM** : 也就是我们上面提到的 Java 虚拟机。 2. **Java 基础类库(Class Library)**:一组标准的类库,提供常用的功能和 API(如 I/O 操作、网络通信、数据结构等)。 JDK(Java Development Kit)是一个功能齐全的 Java 开发工具包,供开发者使用,用于创建和编译 Java 程序。它包含了 JRE(Java Runtime Environment),以及编译器 javac 和其他工具,如 javadoc(文档生成器)、jdb(调试器)、jconsole(监控工具)、javap(反编译工具)等。  > 图片源自:https://oss.javaguide.cn/github/javaguide/java/basis/jdk-include-jre.png ## 基础数据类型 Java 中有 8 种基本数据类型,分别为: - 6 种数字类型: - 4 种整数型:`byte`、`short`、`int`、`long`,占用字节分别是:1字节、2字节、4字节、8字节 - 2 种浮点型:`float`、`double,`,占用字节分别是4字节,8字节 - 1 种字符类型:`char`,2字节 - 1 种布尔型:`boolean`,true/false 这八种基本类型都有对应的包装类分别为:`Byte`、`Short`、`Integer`、`Long`、`Float`、`Double`、`Character`、`Boolean`。 ### 基本类型与包装类的区别是? 我觉得主要区别在于代码的复用性,与前端的JavaScript不同,JavaScript通过原型链实现复用,而Java则主要通过类的继承实现,子类继承父类的方法,因此包装类可以使用父类的方法,如:map、filter……,但基本类型不行 ## 面向对象 ### 三大特性 面向对象的三大特性: - 封装:通过 private 修饰属性,提供 getter/setter 方法控制访问,隐藏内部实现细节 - 继承:子类继承父类的属性与方法,提高了代码的复用性 - 多态:子类重写父类的方法,后续调用时使用子类重写后的方法,提高了代码的灵活性和可扩展性 ### this 关键字 类可以有多个实例,this 关键字便指向实例本身 ### this与静态方法、静态变量 在 Java 中通过 static 修饰的属性称为静态变量,通过 static 修饰的方法称为静态方法,两者的共同特点是:全局属性/全局方法  > 图片源自:https://oss.javaguide.cn/github/javaguide/java/basis/java-basis-variables-static-variable.png 而 this 是指向实例本身,因此静态方法是没有this的,只能访问静态变量,不能直接访问实例成员 ### 重写与重载 重写:实现面向对象多态的基础,子类继承父类方法时,可进行重写,后续方法使用时,查找方法从子类到父类逐步往上查找,此时子类重写了父类的方法,可直接使用,不会经过父类的方法 重载:多个同名方法,但不同参数,根据参数选择对应的方法 ### 抽象类与接口的区别 抽象类与接口的主要区别是,一个类只能继承一个抽象类(Java不支持多继承),但一个类却可以实现多个接口 ### 浅拷贝与深拷贝的区别 两者的区别主要体现在引用数据类型,浅拷贝会拷贝引用数据类型的地址值,而深拷贝则完全拷贝一个对象,并将堆中的对象也拷贝一份  > 图片源自:https://oss.javaguide.cn/github/javaguide/java/basis/shallow&deep-copy.png ### 为什么重写 equals() 时必须重写 hashCode() > 参考:[Java equals() 和 hashCode() 详解](https://www.cnblogs.com/skywang12345/p/3324958.html?utm_source=chatgpt.com) #### equals() 方法 `equals()` 定义在 Java 的 `Object` 类中,默认通过 `==` 判断两个引用是否指向同一个对象 ```Java public boolean equals(Object obj) { return this == obj; } ``` 但实际开发中,我们可能希望两个不同对象的属性相同,也认为它们相等,因此需要重写 `equals()` 例如: ```Java Person p1 = new Person("Tom", 20); Person p2 = new Person("Tom", 20); System.out.println(p1 == p2); // false System.out.println(p1.equals(p2)); // true(重写 equals 后) ``` 重写示例: ```Java @Override public boolean equals(Object obj) { if (this == obj) return true; // 同一个对象 if (obj == null || getClass() != obj.getClass()) return false; Person person = (Person) obj; return age == person.age && Objects.equals(name, person.name); // 不同对象比较属性是否相同 } ``` #### hashCode() 方法 `hashCode()` 同样定义在 `Object` 类中,用于返回对象的哈希码(`int` 类型),主要用于 `HashSet`、`HashMap` 等哈希集合,辅助快速定位元素,以 `HashSet` 为例,底层基于 `HashMap` 实现,添加元素时: 1. 计算哈希值:调用 `hashCode()`,经过处理后确定数组桶的位置 2. 检查桶内元素: - 桶为空:直接插入 - 桶不为空:检查已有节点的哈希码 - 哈希码相同:进一步通过 `==` 或 `equals()` 判断是否相等 3. 决定是否插入: - 存在相等元素:拒绝插入 - 不存在相等元素:插入新节点 注意:不同哈希码也可能映射到同一个桶,但不会因此直接调用 `equals()` 比较 #### 为什么重写 equals() 必须重写 hashCode() 假设 `Person` 只重写了 `equals()`,没有重写 `hashCode()` ```Java Person p1 = new Person("Tom", 20); Person p2 = new Person("Tom", 20); System.out.println(p1.equals(p2)); // true HashSet set = new HashSet(); set.add(p1); set.add(p2); System.out.println(set.size()); // 可能为 2 ``` 问题原因: - `p1` 和 `p2` 属性相同,`equals()` 返回 `true` - 但默认 `hashCode()` 通常根据对象身份生成哈希码,两者可能不同 - `HashSet` 根据不同哈希码定位元素,可能将两个对象都插入集合,导致去重失败 解决方法:同时重写 `hashCode()`,使用与 `equals()` 相同的属性计算哈希码 ```Java @Override public int hashCode() { return Objects.hash(name, age); } ``` 此时: ```Java p1.equals(p2); // true p1.hashCode() == p2.hashCode(); // true ``` `HashSet` 就能正确识别两个逻辑上相等的对象,最终 `set.size()` 为 `1` 总的来说,重写 hashCode 是为了处理当两个对象相同时,哈希表不重复添加元素 #### 总结 - `equals()`:判断两个对象在逻辑上是否相等 - `hashCode()`:生成哈希码,帮助哈希表快速定位对象 - 重写 `equals()` 时必须同时重写 `hashCode()`,保证相等对象具有相同哈希码 - `hashCode()` 相同不代表对象相等,仍需通过 `equals()` 进一步判断 核心:`equals()` 负责判断对象是否相等,`hashCode()` 负责辅助定位对象,两者必须遵守一致的相等性规则,才能保证哈希集合正常工作 ## String、Stringbuilder、Stringbuffer > 文档:https://javaguide.cn/java/basis/java-basic-questions-02.html#%E2%AD%90%EF%B8%8F-string%E3%80%81stringbuffer%E3%80%81stringbuilder-%E7%9A%84%E5%8C%BA%E5%88%AB 都是用来处理字符串的,但 String 不可变,每次修改都会生成新的对象,并将引用指向新的实例(即新的St
以上内容来自博客订阅源,版权归原作者。关注作者后可以在 关注列表 第一时间查看作者文章。

登录后,加入这场讨论。
登录参与