目录
1.3 重载(Overload)与重写(Override)的区别
2.2 JRE(Java Runtime Environment)
3.1 字节码(Bytecode)和 JVM(Java 虚拟机)
3.5 Java 的 "平台无关" 是通过 JDK 和 JVM 的组合实现的
10. String、StringBuffer、StringBuilder 的区别?
12.4 如何在父类中为子类自动完成所有的 hashCode 和 equals 实现?这么做有何优劣?
12.5 说一说你对 java.lang.Object 对象中 hashCode 和 equals 方法的理解。在什么场景下需要重新实现这两个方法?
12.5.3 为什么需要重新实现 hashCode() 和 equals() 方法?
12.5.4 在什么场景下需要重新实现 hashCode() 和 equals() 方法?
12.5.5 如何实现 hashCode() 和 equals() 方法?
示例:重写 equals() 和 hashCode() 方法
13. final、finally、finalize 的区别?
22. error 和 exception 有什么区别?CheckedException 和 RuntimeException 有什么区别?
1. 什么是面向对象?
1.1 面向对象的特征
面向对象编程(OOP)的核心特征是封装、继承、多态和抽象。这四大特性是 OOP 的基石,帮助实现代码的模块化、可复用性、可扩展性和可维护性。
1.1.1 封装(Encapsulation):
封装是将数据和操作数据的方法捆绑到一起,隐藏对象内部的实现细节,只暴露必要的接口(方法)供外部使用。在 Java 中,封装通常通过使用访问控制符(如 private
, public
, protected
)来实现。封装的好处包括:
- 数据保护:通过限制直接访问对象的属性,保护对象的状态不被非法修改。
- 代码模块化:对象只暴露必要的方法,减少外部对内部实现的依赖,增强代码的维护性。
- 灵活性和可扩展性:对象内部实现可以改变,但外部接口不变,保证了程序的可扩展性。
1.1.2 继承(Inheritance):
继承允许新类从现有类中获取属性和方法。通过继承,子类可以复用父类的代码,并且可以在此基础上扩展或修改行为。继承的优点包括:
- 代码复用:避免了代码重复,减少了开发和维护成本。
- 扩展性:可以通过继承为现有类添加新特性,而不需要修改原有代码。
1.1.3 多态(Polymorphism):
多态是指不同对象对同一消息做出不同的响应。在 Java 中,多态主要通过方法重载(同名不同参数)和方法重写(子类重写父类方法)实现。多态的优点包括:
- 灵活性:同一操作可以作用于不同类型的对象,增强了程序的灵活性。
- 可扩展性:新增子类时,不必修改调用代码,只需扩展新的子类即可。
1.1.4 抽象(Abstraction):
抽象是指通过提取对象的共性特征,忽略具体实现细节,定义出类的接口。Java 中通过抽象类和接口实现抽象。抽象的优点包括:
- 简化复杂性:通过抽象屏蔽掉不必要的细节,使得开发者只关注对象的核心行为。
- 可扩展性:不同的实现可以通过统一的接口进行访问,增强系统的灵活性。
1.2 面向对象与面向过程的区别
面向过程 |
面向对象 |
以过程(函数)为核心,强调数据处理流程。 |
以对象(类)为核心,强调数据与操作的封装。 |
更注重程序执行的顺序,适用于结构化的程序。 |
通过封装、继承、多态等特性提高代码的灵活性和扩展性。 |
程序分为一系列的步骤或函数,数据是全局共享的。 |
程序分为多个独立的对象,每个对象拥有自己的数据和方法。 |
开发过程中维护较为困难,尤其在大型系统中。 |
通过封装和模块化,提高了系统的可维护性和可扩展性。 |
性能更高,适合需要高度优化的系统。 |
性能相对较低,但提供了更高的代码可维护性和复用性。 |
1.3 重载(Overload)与重写(Override)的区别
1.3.1 重写(Override)
是指子类重新定义父类中已存在的方法。重写的条件是:方法名、参数列表和返回值类型必须与父类的方法完全相同。
注意:子类方法不能缩小父类方法的访问权限;子类方法可以抛出比父类方法更少的异常(或者不抛出异常)。
class Animal {
void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
1.3.2 重载(Overload)
是指同一方法名可以根据不同的参数列表(参数个数、类型或顺序)定义多个方法。重载的目的是提供多种功能类似但参数不同的方法。
注意:重载方法只能通过方法的参数类型、个数或者顺序的不同来区分,返回值类型不能成为区分重载的方法的依据。
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
}
1.4 构造方法、构造方法重载与拷贝构造方法
1.4.1 构造方法
构造方法是类中的特殊方法,用于在创建对象时初始化对象的状态。构造方法的名称与类名相同,没有返回值类型。
如果没有显式定义构造方法,Java 会提供一个默认的构造方法(无参数构造方法),用于初始化对象。
class Car {
String model;
// 构造方法
public Car(String model) {
this.model = model;
}
}
1.4.2 构造方法重载
在同一个类中,可以定义多个构造方法,这些构造方法有不同的参数列表。这被称为构造方法重载。
每个构造方法可以初始化不同的属性。
class Car {
String model;
int year;
// 构造方法1
public Car(String model) {
this.model = model;
}
// 构造方法2
public Car(String model, int year) {
this.model = model;
this.year = year;
}
}
1.4.3 拷贝构造方法:
在 C++ 中,拷贝构造方法用于通过已有对象创建新对象,而 Java 中并没有自动生成拷贝构造方法。当需要手动实现拷贝构造时,可以通过创建一个新对象并复制已有对象的属性来实现。
在 Java 中,如果想要实现类似于拷贝构造的功能,通常会编写一个构造方法,接受同类型的对象作为参数,并复制其属性。
class Car {
String model;
int year;
// 拷贝构造方法
public Car(Car other) {
this.model = other.model;
this.year = other.year;
}
}
2. JDK、JRE、JVM
2.1 JDK(Java Development Kit)
定义:JDK 是 Java 开发工具包,包含了开发 Java 程序所需的所有工具和库。
内容:JDK 包含了:
- JRE:JDK 中包含了 JRE,JRE 是运行 Java 程序的环境。
- JVM:JDK 内含 JVM,用于执行 Java 字节码。
- 开发工具:如
javac
(编译器,用于将 Java 源代码编译为字节码),javadoc
(用于生成文档的工具),java
(用于运行字节码的命令)等。
用途:JDK 是 Java 开发人员必需的环境,它提供了所有的开发工具,包括编译、调试、运行 Java 程序所需的工具。
2.2 JRE(Java Runtime Environment)
定义:JRE 是 Java 运行时环境,提供了运行 Java 程序所需的最小环境。
内容:
- JVM:JRE 中包含 JVM,负责执行 Java 字节码。
- 类库:JRE 提供了 Java 程序运行所需的核心类库(如
java.lang
,java.util
,java.io
等),它们包含了 Java 程序的基本功能。
用途:JRE 是普通用户运行 Java 程序时需要的环境,它包含了运行 Java 程序所需的所有资源,但不包含开发工具,如编译器等。
2.3 JVM(Java Virtual Machine)
定义:JVM 是 Java 虚拟机,负责执行 Java 程序中的字节码文件(.class
文件)。
功能:JVM 提供了一种跨平台的执行环境,能够将 Java 字节码转换为特定平台的机器代码,使得 Java 程序能够在不同操作系统上运行。JVM 负责:
- 加载字节码文件。
- 执行字节码。
- 管理内存(如垃圾回收)。
- 处理异常等。
2.4 它们之间的关系
JDK 包含 JRE,即 JDK 是一个包含 JRE 和开发工具的开发套件。
JRE 包含 JVM,即 JRE 是为运行 Java 程序所需的运行时环境,而 JVM 是 JRE 中的核心组件,负责执行 Java 字节码。
简单来说:
- JDK 提供了开发 Java 程序所需的工具和环境。
- JRE 提供了运行 Java 程序所需的环境。
- JVM 是 JRE 中的执行引擎,负责运行 Java 程序的字节码。
3. 为什么 Java 被称作是“平台无关的编程语言”?
Java 被称为“平台无关的编程语言”,其原因主要归功于 Java 的 "一次编写,到处运行" 的特性,这意味着 Java 程序可以在不同的操作系统和硬件平台上运行,而无需修改源代码。这个特性是通过以下几个关键因素实现的:
3.1 字节码(Bytecode)和 JVM(Java 虚拟机)
Java 程序在编译时并不是直接编译为操作系统特定的机器代码,而是编译为 字节码(.class
文件),这是一种与平台无关的中间代码。
这些字节码被 JVM(Java Virtual Machine) 执行。JVM 是一个运行时环境,它将 Java 字节码转换为特定平台(如 Windows、Linux、macOS)的机器代码。
JVM 的存在使得同一份 Java 字节码可以在任何安装了 JVM 的平台上运行,而无需修改代码,因此 Java 程序具有跨平台性。
3.2 JVM 的平台适配性
不同的操作系统(Windows、Linux、macOS 等)都可以有自己特定的 JVM 实现。每个 JVM 实现都能够将 Java 字节码转换为对应平台的机器代码,使得 Java 程序能够在不同的操作系统上运行。
Java 的平台无关性并不是指 Java 语言本身没有平台依赖,而是通过 JVM 来解决不同操作系统之间的差异。
3.3 Java 核心库(API)的跨平台设计
Java 提供了大量跨平台的标准库(如 java.lang
, java.util
, java.io
等),这些库提供的功能都是针对不同平台的通用实现,不依赖于底层操作系统。
Java 程序可以直接使用这些库进行开发,避免了针对特定操作系统的开发和调试。
3.4 JRE 和 JDK
JRE(Java 运行时环境)和 JDK(Java 开发工具包)都提供了跨平台的 Java 环境。只要安装了 JRE 或 JDK,不同操作系统上都可以运行相同的 Java 程序。
3.5 Java 的 "平台无关" 是通过 JDK 和 JVM 的组合实现的
通过将 Java 源代码编译成与平台无关的字节码,Java 不需要针对每个操作系统重新编写程序。无论是 Windows、Linux、macOS 还是其他操作系统,只要在这些平台上安装了对应的 JVM,Java 程序就能运行。
3.6 举个例子:
- 你编写的 Java 程序首先在 Windows 操作系统上通过
javac
编译成字节码文件(.class
)。 - 然后,你将该
.class
文件传输到 Linux 系统上。 - 在 Linux 系统上,只要安装了 JVM,你就可以直接用
java
命令运行字节码文件,无需重新编译。JVM 会将字节码转换为 Linux 系统可以执行的机器代码。
4. JDK8 引入了什么重要的特性?
- Lambda 表达式:引入了函数式编程的支持,使代码更加简洁和灵活。
- Streams API:提供了一种更高效、声明式的数据处理方式,支持流式处理集合。
- 默认方法:接口可以有默认实现方法,这为 API 扩展提供了方便。
- 新的日期和时间 API(
java.time
):解决了java.util.Date
和java.util.Calendar
的问题。 - Optional:用于避免 null 值带来的空指针异常。
- 并行 Stream:可以在多核处理器上并行操作集合数据。
5. 什么是字节码?采用字节码的最大好处是什么?
5.1 什么是字节码?
字节码(Bytecode)是 Java 编程语言源代码编译后的中间表示形式,它不是直接针对某个平台的机器代码,而是设计为可以在任何支持 Java 虚拟机(JVM)上的平台运行的中间代码。字节码由 Java 编译器(javac
)生成,文件扩展名为 .class
,这些文件包含了类的字节码,而 JVM 会将这些字节码解释为平台特定的机器代码来执行。
5.2 采用字节码的最大好处是什么?
采用字节码的最大好处是 平台无关性,即 "一次编写,到处运行" 的能力。这是字节码的核心特性。具体来说,字节码带来了以下几方面的好处:
5.2.1 跨平台性:
Java 源代码在编译时生成的字节码(.class
文件)是与操作系统和硬件架构无关的中间代码。
通过 Java 虚拟机(JVM)的实现,字节码可以在任何安装了 JVM 的操作系统和硬件平台上运行,而无需修改或重新编译代码。
这使得 Java 程序可以轻松地在不同的操作系统(如 Windows、Linux、macOS)上运行,符合 Java 提出的 "一次编写,到处运行" 的口号。
5.2.2 提高性能:
字节码的引入使得 Java 程序可以通过 JIT(即时编译) 技术,在运行时将字节码动态编译为目标平台的机器代码,优化性能。
JVM 可以在运行时优化字节码,例如通过方法内联、热点代码优化等技术,提高执行效率。
5.2.3 增强安全性:
字节码在执行时可以通过 JVM 的安全管理机制进行检查和验证。这些机制可以避免一些低级的错误(如直接访问内存)和潜在的恶意代码的执行。
JVM 通过字节码验证来确保程序的安全性,防止直接在操作系统上执行未经授权的指令。
5.2.4 与硬件解耦:
字节码使得开发人员无需关心底层硬件架构的差异,开发人员只需关注 Java 语言本身,JVM 会处理与硬件和操作系统相关的具体实现。
这种解耦机制使得 Java 成为非常适合 分布式系统 和 云计算 环境的语言。
5.2.5 支持反射与动态特性:
字节码为 Java 提供了反射(Reflection)机制,通过反射,Java 可以动态地分析和修改类、方法和字段的行为,进一步增强了 Java 的灵活性和扩展性。
5.2.6 代码优化与执行控制:
通过字节码,JVM 可以进行多种执行优化(如垃圾回收、内存管理、JIT 编译等),保证程序高效运行。
6. Java 中的基本数据类型及其占用字节数
Java 提供了八种基本数据类型,每种数据类型有特定的字节大小:
6.1 整数类型:
byte
:1 字节(8 位)short
:2 字节(16 位)int
:4 字节(32 位)long
:8 字节(64 位)
6.2 字符类型:
char
:2 字节(16 位)char
类型采用 Unicode 编码,每个字符使用 2 字节表示,因此 Java 中的char
类型可以存储一个汉字(Unicode 编码字符)。
6.3 浮点类型:
float
:4 字节(32 位)double
:8 字节(64 位)
6.4 布尔类型:
boolean
:Java 中没有明确规定布尔类型占用的字节数,通常实现是 1 字节,但逻辑上它是表示 true 或 false 的两种状态。