Java基础面试题2

面向对象编程(OOP)是 Java 的核心思想,掌握其关键概念是学好 Java 的基础。本文将系统梳理面向对象的核心知识点,包括核心定义、三大特征、重载与重写、抽象类与接口、final 关键字、深浅拷贝等,帮助大家建立完整的知识体系。

一、面向对象基础:什么是对象与类?

1. 核心定义

  • :是对一类事物的抽象描述,包含该类事物的属性(数据)和行为(方法),是创建对象的 "模板"。
  • 对象:是类的运行实例,是堆内存中一块具体的内存空间,包含类定义的属性和方法的具体实现。

简单来说:类是 "图纸",对象是根据图纸造出的 "实物"。

2. 面向对象三大核心特征

(1)封装

封装是指将对象的属性(数据)和行为(方法)结合在一起,对外隐藏对象的内部细节,仅通过对象提供的接口与外界交互。

  • 核心价值:提高代码安全性(避免属性被随意修改)、降低耦合度。
  • 实现方式:属性私有化(private 修饰),通过 get/set 方法暴露访问接口。
(2)继承

继承的本质是代码复用,子类(派生类)可以使用父类(基类)的非私有属性和方法,无需重复编写。

  • 核心价值:减少代码冗余,实现代码复用。
  • 关键字:extends(Java 中仅支持单继承)。
  • 注意:子类只能继承父类的非私有成员,构造方法不能被继承,但子类构造方法会默认调用父类无参构造。
(3)多态

多态是指允许不同类的对象对同一消息作出响应,核心体现为 "一个接口,多种实现"。

  • 实现形式
    • 方法重载(同一类内)
    • 方法重写(子类对父类)
    • 接口与实现类
    • 向上转型(父类引用指向子类对象)

二、核心概念辨析:重载 vs 重写

表格

特性 方法重载(Overload) 方法重写(Override)
定义位置 同一个类中 子类与父类之间
方法名 必须相同 必须相同
参数列表 必须不同(类型 / 个数 / 顺序) 必须完全相同
返回值 无强制要求(JDK5 + 支持协变返回类型) 必须与父类一致(或子类类型,协变返回)
访问修饰符 无特殊限制 不能缩小父类方法的访问权限(如父类 public,子类不能 private)
异常 无强制要求 不能抛出比父类更多的检查异常
关键字 无专属关键字 推荐使用 @Override 注解(编译器校验)
绑定时机 编译期绑定(静态多态) 运行期绑定(动态多态)

示例代码

java

运行

复制代码
// 方法重载示例
class OverloadDemo {
    // 重载1:无参数
    public void print() {
        System.out.println("无参print方法");
    }
    
    // 重载2:int参数
    public void print(int num) {
        System.out.println("int参数print方法:" + num);
    }
    
    // 重载3:String参数
    public void print(String str) {
        System.out.println("String参数print方法:" + str);
    }
}

// 方法重写示例
class Parent {
    public void sayHello() {
        System.out.println("父类:Hello");
    }
}

class Child extends Parent {
    // 重写父类方法
    @Override
    public void sayHello() {
        System.out.println("子类:Hello");
    }
}

三、抽象类与接口:抽象化的两种实现

1. 抽象类 vs 普通类

特性 普通类 抽象类
实例化 可直接 new 创建对象 不能直接实例化,仅能被继承
方法 仅包含有实现的普通方法 可包含普通方法 + 抽象方法
设计目的 直接创建对象使用 作为基类,供子类扩展复用

2. 抽象类与接口的区别与共同点

(1)共同点
  • 都不能被直接实例化;
  • 都用于定义规范(抽象方法);
  • 都支持多态(向上转型)。
(2)核心区别
特性 抽象类 (Abstract Class) 接口 (Interface)
实现 / 继承方式 extends(单继承) implements(多实现)
方法 可包含普通方法(有实现)+ 抽象方法(无实现) JDK8 前:仅抽象方法;JDK8 后:可加 default/static 方法
成员变量 支持实例变量、静态变量,修饰符灵活 仅 public static final 常量(必须赋初值)
构造方法 有构造方法(供子类调用) 无构造方法
访问修饰符 方法 / 变量支持 public/protected/private 方法默认 public abstract,变量默认 public static final
设计目的 强调 "is-a" 继承关系,侧重代码复用 强调 "has-a" 行为规范,侧重解耦和扩展

3. 关键补充

  • 抽象方法:由 abstract 修饰,无方法体,子类继承抽象类必须重写所有抽象方法;
  • 抽象类不能用 final 修饰:抽象类的核心是被继承,final 修饰的类无法被继承,二者矛盾;
  • 抽象类有构造器:不能直接实例化,但子类创建对象时会调用父类构造器,实现间接实例化。

四、final 关键字:限制修改的核心

final 意为 "最终的",核心作用是限制修改,有三大应用场景:

1. 修饰类

被 final 修饰的类无法被继承,例如 Java 中的 String 类:

复制代码
final class FinalClass {
    // 此类不能被继承
}
// 编译报错:无法继承final类
// class SubClass extends FinalClass {}

2. 修饰方法

被 final 修饰的方法无法被子类重写:

复制代码
class Parent {
    public final void finalMethod() {
        System.out.println("此方法不能被重写");
    }
}

class Child extends Parent {
    // 编译报错:无法重写final方法
    // @Override
    // public void finalMethod() {}
}

3. 修饰变量

被 final 修饰的变量无法重新赋值:

  • 基本数据类型:值不可变;

  • 引用数据类型:引用地址不可变,但对象内容可变。

    // 基本类型常量
    final int NUM = 10;
    // NUM = 20; // 编译报错:不能重新赋值

    // 引用类型
    final StringBuilder sb = new StringBuilder("Hello");
    sb.append(" World"); // 合法:对象内容可修改
    // sb = new StringBuilder("New"); // 编译报错:引用地址不可变

五、static 关键字:属于类的成员

static 修饰的成员(变量 / 方法 / 代码块 / 内部类)属于类本身,而非对象。

1. 静态变量

  • 共享性:所有类实例共享同一个静态变量,一个实例修改,所有实例可见;
  • 初始化时机:类加载时初始化,仅初始化一次;
  • 访问方式:推荐通过类名访问(类名。静态变量),也可通过对象访问(不推荐)。

2. 静态方法

  • 无实例依赖:无需创建对象即可调用(类名。静态方法);
  • 访问限制:不能直接访问非静态成员(无 this 引用),可直接访问静态成员;
  • 多态特性:不支持重写(Override),仅能被隐藏(Hide)。

3. 其他应用

  • 静态代码块:类加载时执行,用于初始化静态变量,优先于 main 方法执行;
  • 静态内部类:不依赖外部类实例,可独立存在,不能直接访问外部类非静态成员。

六、深浅拷贝:对象复制的核心区别

1. 核心定义

  • 浅拷贝:仅拷贝对象的引用地址,原对象和拷贝对象共享同一块堆内存,原对象属性修改会影响拷贝对象;
  • 深拷贝:拷贝对象的所有属性(包括引用类型),原对象和拷贝对象拥有独立的堆内存,修改互不影响。

2. 深拷贝的三种实现方式

(1)实现 Cloneable 接口,重写 clone () 方法
复制代码
class Person implements Cloneable {
    private String name;
    private Address address; // 引用类型属性

    // 深拷贝重写clone方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person clone = (Person) super.clone();
        // 对引用类型属性单独拷贝
        clone.address = (Address) address.clone();
        return clone;
    }
}

class Address implements Cloneable {
    private String city;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
(2)序列化与反序列化

通过 Serializable 接口实现对象的完整拷贝:

复制代码
import java.io.*;

class Person implements Serializable {
    private String name;
    private Address address;

    // 深拷贝方法
    public Person deepClone() throws IOException, ClassNotFoundException {
        // 序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        
        // 反序列化
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (Person) ois.readObject();
    }
}

class Address implements Serializable {
    private String city;
}
(3)手动递归复制

手动创建新对象,逐个拷贝所有属性(包括引用类型属性):

复制代码
class Person {
    private String name;
    private Address address;

    // 手动深拷贝
    public Person deepCopy() {
        Person newPerson = new Person();
        newPerson.name = this.name;
        // 手动创建引用类型的新对象
        Address newAddress = new Address();
        newAddress.setCity(this.address.getCity());
        newPerson.address = newAddress;
        return newPerson;
    }
}

七、补充:为什么 Java 只支持单继承?

Java 设计为单继承(一个类只能继承一个父类),核心原因:

  1. 避免菱形继承问题:多继承可能导致父类方法冲突(子类无法确定调用哪个父类的方法);
  2. 简化类结构:单继承让类的继承关系更清晰,降低代码复杂度;
  3. 减少资源浪费:创建子类对象时会递归创建父类对象,多继承会增加内存开销和初始化复杂度;
  4. 接口补充扩展:通过接口的多实现机制,既规避了多继承的问题,又满足了扩展需求。
相关推荐
马猴烧酒.1 小时前
【JAVA算法|hot100】贪心算法类型题目详解笔记
java·开发语言·ide·笔记·算法·spring·贪心算法
语戚1 小时前
深入浅出 AOP:织入时机、JDK 动态代理与 CGLIB 原理及 Spring 选择策略
java·开发语言·spring·jdk·代理模式·aop·动态代理
啦啦啦_99991 小时前
9. AI面试题之 功能代码实现
java·人工智能
bubiyoushang8881 小时前
基于MATLAB的可见光通信(VLC)发射端:电-光转换与LED驱动仿真
开发语言·matlab
vx-程序开发1 小时前
springboot具备推荐和预警机制的大学生兼职平台的设计与实现-计算机毕业设计源码17157
java·c++·spring boot·python·spring·django·php
EnCi Zheng2 小时前
11a. 阿里云大模型API调用基础
人工智能·python·阿里云·云计算
伍一512 小时前
星云ERP免编译安装包分享,可直接运行,附完整程序包下载地址
java
逆境不可逃2 小时前
LeetCode 热题 100 之 279. 完全平方数 322. 零钱兑换 139. 单词拆分 300. 最长递增子序列
java·算法·leetcode·职场和发展
shamalee2 小时前
Spring Security 新版本配置
java·后端·spring