目录
5.为什么 Java 不支持多重继承?但是支持多实现?(易)
8.Java 中 Exception 和 Error 有什么区别?(中)
9.Java 面向对象编程与面向过程编程的区别是什么?(中)
1.Java 的优势是什么?(易)
- 跨平台:可以通过jvm实现,一次编写,处处运行,可移植性强
- 垃圾回收:自动回收内存,提高内存管理效率
- 生态:拥有丰富的资料、第三方类库、企业级框架等等
- 面向对象:Java语言拥有类、对象、接口等概念,且支持封装、继承、多态等OOP特性
2.什么是 Java 的多态特性?(中)
- 多态是指同一个接口或父类引用变量可以指向不同的对象实例,并跟据实际指向的对象类型执行相应的方法,同时允许同一方法在不同对象上表现出不同的行为,是面向对象编程的三大特性之一。
- 多态分为两种类型:
1.编译时多态:通过方法重载实现,在编译时确定方法的调用。
2.运行时多态:通过方法重写实现,在运行时确定方法的调用。
- 多态优点:降低代码耦合度,增强代码可扩展性,符合开闭原则。
class Animal {
void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Dog(); // 多态
myAnimal.makeSound(); // 输出"Bark"
}
}
3.Java 中的参数传递是按值还是按引用?(中)
在Java中,参数传递始终时按值传递。如:
- 基本数据类型(int, float, boolean 等):传递的是值的副本,方法内修改不会影响原始值。
- 引用数据类型(对象、数组等):传递的是引用的副本,即引用的值,方法内可以修改对象的状态,但不能让原始引用指向新对象来修改属性。
void modify(int x, List<String> list) {
x = 10; // 不影响原始x
list.add("new"); // 修改了原始list指向的对象
list = null; // 不影响原始list引用
}
4.接口和抽象类有什么区别?(易)
- 设计思路:接口的设计是先约定接口,再实现,抽象类的设计是先有一些类,才抽象了共同父类。
- 方法实现:接口中Java 8前只能有抽象方法,之后可以有默认方法,抽象类中可以有抽象方法和具体实现方法
- 构造方法:接口不能含有构造函数,抽象类可以有。
- 成员变量:接口只能是 public static final 常量,而抽象类可以有非常量的普通成员变量。
特性 | 接口(Interface) | 抽象类(Abstract Class) |
---|---|---|
实现方式 | 使用 interface 关键字 | 使用 abstract class 关键字 |
方法实现 | Java 8前只能有抽象方法,之后可以有默认方法 | 可以有抽象方法和具体实现方法 |
变量 | 只能是 public static final 常量 | 可以有普通成员变量 |
构造方法 | 不能有构造方法 | 可以有构造方法 |
继承 | 一个类可以实现多个接口 | 一个类只能继承一个抽象类 |
设计目的 | 定义行为规范/契约 | 提供部分实现的模板 |
访问修饰符 | 方法默认 public | 方法可以有各种访问修饰符 |
使用场景 | 需要多继承或定义行为契约时 | 需要代码复用或提供部分实现时 |
5.为什么 Java 不支持多重继承?但是支持多实现?(易)
- 不支持多重继承主要是避免产生菱形继承,比如现在有ABCD四个类,BC继承了A,D又同时继承BC,此时要调用D内定义在A的方法时会产生歧义,因为B和C都对方法有不同的实现。
- 支持多实现是因为Java8之前的接口都必须由子类去实现,因此不会发生歧义,虽然Java8之后出现了默认方法,但是规定如果多个接口内有相同的默认方法,则子类必须重写这个默认方法。
interface A { default void foo() { System.out.println("A"); } }
interface B { default void foo() { System.out.println("B"); } }
class C implements A, B {
@Override // 必须重写解决冲突
public void foo() {
A.super.foo(); // 可以明确选择调用哪个版本
}
}
6.Java 中的序列化和反序列化是什么?(易)
- 序列化(Serialization):将 Java 对象转换为字节序列的过程,以便存储或传输。
- 反序列化(Deserialization):将字节序列重新转换为 Java 对象的过程。
7.什么是 Java 中的不可变类?(中)
不可变类是指其实例在创建后状态不能被修改的类,所有看似修改的操作实际上都会返回一个新对象。(如String、Integer、BigDecimal、LocalDate)
主要特征:
- 类声明为 final,防止被继承和修改。
- 所有字段设为 private final,禁止外部访问和修改。
- 不提供 setter 方法,杜绝修改途径。
- 通过构造函数初始化所有字段,创建后状态即确定。
- 返回可变对象的防御性拷贝,如getter方法中返回对象的副本(new 一个新对象)来保护可变对象。
public final class ImmutablePerson {
private final String name;
private final int age;
private final List<String> hobbies;
public ImmutablePerson(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
this.hobbies = Collections.unmodifiableList(new ArrayList<>(hobbies));
}
// 只有getter方法
public List<String> getHobbies() {
return new ArrayList<>(hobbies); // 防御性拷贝
}
}
8.Java 中 Exception 和 Error 有什么区别?(中)
- 都是Throwable的子类。
- Exception表示可以被处理的程序异常,分为检查型异常(Checked Exception)和运行时异常(Unchecked Exception),检查型异常必须被捕获或声明抛出(如IOException),运行时异常通常不需要显示捕获。
- Error表示系统级的不可恢复错误,通常不应尝试捕获,由JVM抛出,指示系统级故障或资源耗尽。
特性 | Exception (异常) | Error (错误) |
---|---|---|
可恢复性 | 通常可以捕获并处理 | 通常不可恢复,程序应当终止 |
产生原因 | 由应用程序逻辑引起 | 由JVM或系统底层资源问题引起 |
处理建议 | 应该被捕获并适当处理 | 通常不推荐捕获,应修正根本问题 |
继承关系 | 继承自 java.lang.Exception | 继承自 java.lang.Error |
典型例子 | IOException, SQLException | OutOfMemoryError, StackOverflowError |
9.Java 面向对象编程与面向过程编程的区别是什么?(中)
- 面向对象编程(OOP):是一种以对象为中心的编程风格,把类或者对象作为基本单元来组织代码,并且运用封装、继承、多态特性来指导代码设计,注重对象之间的交互和模块化设计。
- 面向过程编程(POP):是一种以过程或函数为中心的编程风格,把过程或函数作为基本单元来组织代码,注重逻辑的分步实现。
比较维度 | 面向对象编程 (OOP) | 面向过程编程 (POP) |
---|---|---|
基本单元 | 对象(类和实例) | 函数/过程 |
核心思想 | 封装、继承、多态 | 算法和步骤分解 |
数据与行为关系 | 数据和方法绑定在对象中 | 数据和方法分离 |
典型特性 | 类、对象、接口、继承、多态 | 函数调用、顺序执行、条件分支 |
代码复用方式 | 通过继承和组合 | 通过函数调用 |
典型语言 | Java, C++, Python | C, Pascal, BASIC |
适合场景 | 大型复杂系统,需求易变 | 小型程序,性能敏感型应用 |
状态管理 | 对象内部维护状态 | 通过参数传递状态 |
10.Java 方法重载和方法重写之间的区别是什么?(易)
- 方法重载(Overload):在同一个类中,允许有多个同名方法,只要它们的参数列表不同(参数个数、类型或顺序)。主要关注方法的签名变化,适用于在同一类中定义不同场景下的行为。
- 方法重写(Override):子类在继承父类时,可以重写父类的某个方法(参数列表、方法名必须相同) ,从而为该方法提供新的实现。主要关注继承关系,用于子类改变父类的方法实现,实现运行时多态性。
比较维度 | 方法重载 (Overload) | 方法重写 (Override) |
---|---|---|
定义位置 | 同一个类中 | 子类与父类之间 |
方法签名 | 必须不同(参数类型、个数或顺序) | 必须完全相同 |
返回类型 | 可以不同 | 相同或是其子类型(协变返回类型) |
访问修饰符 | 可以不同 | 不能比父类更严格 |
异常抛出 | 可以抛出不同异常 | 不能抛出比父类更宽泛的检查型异常 |
绑定机制 | 编译时静态绑定 | 运行时动态绑定 |
目的 | 提供处理不同类型数据的类似功能 | 实现多态,修改或扩展父类行为 |
重载示例:
class Calculator {
// 方法重载
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
}
重写示例:
class Animal {
void makeSound() { System.out.println("Animal sound"); }
}
class Dog extends Animal {
// 方法重写
@Override
void makeSound() { System.out.println("Bark"); }
}
本文到此结束,如果对你有帮助,可以点个赞~
后续会在合集里持续更新Java相关的面试题,欢迎关注~
祝各位都能拿到满意的offer~