Java面向对象进阶精讲:抽象类、接口、内部类与Object类万字详解

Java面向对象进阶精讲:抽象类、接口、内部类与Object类万字详解

摘要:抽象类、接口、内部类、Object基类是Java面向对象体系的四大核心基石,也是校招、社招Java后端面试必考重难点,在日常业务开发、主流框架(Spring、MyBatis、集合框架)底层源码中随处可见。本文依托经典实战案例:图形体系、动物继承、USB设备驱动、对象比较与克隆,从定义、语法、编译特性、代码示例、使用场景、面试易错点六大维度完整拆解知识点,全文围绕官方语法规范与阿里编码规范展开,兼顾零基础学习与面试备考,总字数超7200字。

前言

在Java面向对象编程体系中,封装、继承、多态是三大核心思想,而抽象类与接口是实现多态最重要的两种载体,内部类是封装思想的延伸实现,Object是Java所有引用类型的顶层祖宗类,四者相辅相成,构成了Java类体系的底层骨架。

很多初学者在入门阶段极易出现几个典型误区:分不清抽象类和接口的使用场景、混淆四种内部类的访问权限与实例化规则、搞不懂equals()hashCode()成对重写的底层规范、不理解Cloneable接口浅拷贝与深拷贝的本质差异。出现问题的根本原因是没有从设计思想层面理解语法诞生的初衷:Java每一个语法设计都是为了解决特定业务痛点,抽象类用来抽取子类通用模板、接口用来定义统一行为规范、内部类用来封装专属局部逻辑、Object统一所有对象的通用行为。

本文分为五大章节:抽象类详解、接口全解、四类内部类剖析、Object顶层类源码解析、课后习题深度拆解,所有代码示例均沿用教材原版案例并补充拓展说明,贴合初学者学习路径。

第一章 抽象类(abstract class)深度剖析

1.1 抽象类设计概念与现实案例

面向对象编程的核心逻辑是通过类描述实体对象,但现实业务中存在大量无法具象化、不能直接生成实体 的概念,这类概念对应的类就被定义为抽象类。文档中给出了两个行业入门标杆案例:图形Shape类、动物Animal类。

案例1:图形体系

矩形、圆形、三角形都属于图形,天然满足继承关系。但"图形"本身是一个抽象概念,没有固定形状,因此绘制方法draw()、计算面积方法calcArea()无法在父类Shape中编写具体实现逻辑,只能交给各个具体子类(圆形、矩形)去实现,因此Shape需要定义为抽象类。

案例2:动物体系

猫、狗都属于动物,具备继承关系,所有动物都拥有鸣叫行为bark(),但抽象的"动物"不存在具象的叫声,只有狗"汪汪汪"、猫"喵喵喵",差异化逻辑只能由子类实现,因此顶层父类Animal设计为抽象类。

基于以上场景,Java语法诞生抽象方法与抽象类 :被abstract修饰、没有方法体{}的方法称为抽象方法;包含任意抽象方法的类必须使用abstract修饰,成为抽象类。抽象类的核心定位:抽取多个子类的公共属性与通用方法,通过抽象方法强制子类实现差异化业务逻辑,依托编译器语法校验规避编码错误。

1.2 抽象类基础语法格式

使用abstract class关键字定义抽象类,抽象类是特殊的类,保留普通类所有特性:可以定义成员变量、普通成员方法、构造方法,仅额外支持抽象方法

java 复制代码
// 抽象图形父类
public abstract class Shape {
    // 抽象方法:abstract修饰,无方法体,强制子类重写
    abstract public void draw();
    abstract void calcArea();

    // 普通成员变量:受访问修饰符管控,protected子类可直接访问
    protected double area;

    // 普通实例方法:拥有完整实现,子类继承后可直接使用无需重写
    public double getArea() {
        return area;
    }

    // 抽象类构造方法
    public Shape(){}
    public Shape(double area){
        this.area = area;
    }
}

编码小提示:抽象方法修饰符public abstract可以任意省略,编译器会自动补全,行业编码习惯简写void draw();,代码更加整洁。

1.3 抽象类六大核心语法特性(面试必背)

抽象类共有6条硬性语法约束,所有编译报错都源于违反下述规则,每条规则搭配错误代码示例与原理说明。

特性1:抽象类禁止直接使用new实例化

抽象类无具体实体,语法层面禁止创建对象,直接new编译报错。

java 复制代码
// 编译错误:Shape是抽象的; 无法实例化
Shape shape = new Shape();

设计目的:杜绝开发者误创建抽象父类对象,在编译期拦截业务逻辑错误,抽象类只能通过实例化子类向上转型使用。

特性2:抽象方法不能使用private修饰

abstractprivate修饰符语法互斥:private修饰的方法对子类不可见,而抽象方法的设计目的就是强制子类重写,无法被重写的抽象方法没有任何存在意义。

java 复制代码
abstract class Shape {
    // 编译报错:非法的修饰符组合: abstract和private
    abstract private void draw();
}
特性3:抽象方法不能被final、static修饰
  1. final修饰方法代表方法锁定、不可被子类重写,和抽象方法必须重写的设计冲突;
  2. static修饰的方法属于类本身,子类重写静态方法本质是方法隐藏,并非真正意义上的重写,不符合抽象方法语法要求。
java 复制代码
public abstract class Shape {
    abstract final void methodA();    // abstract+final非法
    abstract public static void methodB(); // abstract+static非法
}
特性4:子类继承抽象类二选一:重写全部抽象方法 / 子类定义为抽象类

普通实体类继承抽象父类,必须重写父类全部抽象方法;若子类无法完成全部抽象方法实现,当前子类需要添加abstract修饰,升级为抽象类,由下一代子类继续实现剩余抽象方法。

java 复制代码
// 矩形:普通实体类,完整实现Shape所有抽象方法
public class Rect extends Shape {
    private double length;
    private double width;
    Rect(double length, double width){
        this.length = length;
        this.width = width;
    }
    @Override
    public void draw() {
        System.out.println("矩形: length= "+length+" width= " + width);
    }
    @Override
    public void calcArea() {
        area = length * width;
    }
}

// 圆形:普通实体类,完整实现抽象方法
public class Circle extends Shape{
    private double r;
    final private static double PI = 3.14;
    public Circle(double r){
        this.r = r;
    }
    @Override
    public void draw() {
        System.out.println("圆:r = "+r);
    }
    @Override
    public void calcArea() {
        area = PI * r * r;
    }
}

// 三角形:抽象类,仅实现draw(),calcArea()交由直角三角、等腰三角子类实现
public abstract class Triangle extends Shape {
    private double a;
    private double b;
    private double c;
    @Override
    public void draw() {
        System.out.println("三角形:a = "+a + " b = "+b+" c = "+c);
    }
    // 未实现calcArea(),因此类必须加abstract修饰
}
特性5:有抽象方法的类一定是抽象类,抽象类不一定包含抽象方法

该规则是单向约束:只要类内存在abstract抽象方法,类强制abstract修饰;但抽象类可以全部由普通属性、普通方法构成,不含任何抽象方法。

开发场景:项目中部分工具基类被设计为无抽象方法的抽象类,目的就是禁止外部直接new创建基类实例。

特性6:抽象类允许定义构造方法

抽象类构造方法无法在外部直接调用实例化,但子类构造时默认通过super()调用父类构造器,用来初始化从父类继承的成员变量,是子类初始化父类属性的唯一入口。

1.4 抽象类在项目中的实际作用

很多初学者会产生疑问:普通类也可以被继承、子类也能重写普通方法,为什么Java额外设计抽象类语法?

答案:抽象类为代码增加一层编译器校验,提前规避人为编码失误

假设图形父类使用普通class Shape,开发者编写Shape s = new Shape();创建抽象图形对象,编译器不会抛出任何错误,但业务逻辑完全不合理;换成abstract抽象类后,该行代码直接编译报错,在编码阶段就拦截错误。

该设计思想和final关键字异曲同工:final修饰变量防止误修改,抽象类通过语法限制防止误实例化父类,依托JDK编译校验提升项目代码健壮性,这也是Java众多语法的设计共性:从语法层面约束错误写法。

第二章 接口(interface)全方位详解

2.1 接口现实原型与编程概念

现实生活中USB接口、电源插座是接口最直观的案例:USB是统一通信协议规范,鼠标、键盘、U盘只要遵循USB标准,就能接入电脑;电源插座是供电规范,手机充电器、电饭煲符合插孔标准即可通电使用。

映射到Java:接口是一组公共行为规范、功能标准,属于引用数据类型,只定义能力、不关心具体实现 ,类通过implements关键字实现接口,严格遵守接口定义的全部规范。

语义区分:extends继承代表is-a(是什么事物,猫是动物);implements实现代表has-a(具备某种能力,猫具备奔跑能力)。

2.2 接口语法规则与编码规范

将定义类的class替换为interface即完成接口定义,接口内的抽象方法、成员变量全部自带隐式修饰符,阿里Java开发手册明确约定:接口方法、成员变量不手动书写修饰符,依靠默认隐式修饰,保证代码简洁。

java 复制代码
public interface USB {
    // 以下4种写法完全等价,方法默认隐式 public abstract
    public abstract void method1();
    public void method2();
    abstract void method3();
    void method4(); // 企业开发推荐写法

    // 接口变量默认隐式 public static final,定义时必须初始化赋值
    double USB_VERSION = 3.0;
}

接口命名规范:

  1. 功能性接口推荐大写I开头:IRunning、IFlying;
  2. 接口命名优先使用形容词词性单词,贴合"具备某种能力"的语义。

2.3 接口使用规则:implements实现

接口不能直接实例化,必须由实现类通过implements实现接口所有抽象方法,extends用于类继承,implements用于类实现接口,关键字不可混用。

经典实战案例:笔记本+USB设备(鼠标、键盘),完整落地代码:

java 复制代码
// 1.定义USB接口:规范打开、关闭设备两个标准行为
public interface USB {
    void openDevice();
    void closeDevice();
}

// 2.鼠标实现USB规范,额外独有点击功能
public class Mouse implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }
    // 实现类自定义独有方法
    public void click(){
        System.out.println("鼠标点击");
    }
}

//3.键盘实现USB规范,额外独有输入功能
public class KeyBoard implements USB {
    @Override
    public void openDevice() {
        System.out.println("打开键盘");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭键盘");
    }
    public void inPut(){
        System.out.println("键盘输入");
    }
}

//4.笔记本:方法依赖USB接口,任意实现USB的设备都能接入使用
public class Computer {
    public void powerOn(){
        System.out.println("打开笔记本电脑");
    }
    public void powerOff(){
        System.out.println("关闭笔记本电脑");
    }
    // 面向接口编程:参数写接口类型,利用多态接收所有USB实现类
    public void useDevice(USB usb){
        usb.openDevice();
        // 向下转型调用实现类独有方法
        if(usb instanceof Mouse){
            Mouse mouse = (Mouse)usb;
            mouse.click();
        }else if(usb instanceof KeyBoard){
            KeyBoard keyBoard = (KeyBoard)usb;
            keyBoard.inPut();
        }
        usb.closeDevice();
    }
}

//测试运行
public class TestUSB {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.powerOn();
        computer.useDevice(new Mouse());
        computer.useDevice(new KeyBoard());
        computer.powerOff();
    }
}

案例核心价值:电脑useDevice只依赖USB接口,后续新增U盘、摄像头设备时,只需新建类实现USB接口,原有电脑代码无需任何修改,完美贴合软件开发开闭原则(对扩展开放、对修改关闭)。

2.4 接口九大硬性语法特性

特性1:接口是引用数据类型,禁止new直接实例化
java 复制代码
USB usb = new USB(); // 编译报错:接口无法实例化
特性2:接口抽象方法默认public abstract,不能使用private/protected修饰

接口方法权限被JDK强制锁定为public,私有修饰直接编译报错。

特性3:JDK7及之前接口无带方法体的普通方法,全部为抽象方法

JDK8新增default默认方法、static静态方法,打破该限制,default方法拥有方法体,由实现类对象调用;static方法通过接口名直接调用。

特性4:实现类重写接口方法时,访问权限必须是public

接口方法默认public,子类重写不能缩小访问权限(默认包访问、protected、private全部编译报错)。

java 复制代码
interface USB{void open();}
class Mouse implements USB{
    @Override
    void open(){} // 报错:权限低于public
}
特性5:接口成员变量隐式public static final,属于全局常量
  1. static:可直接通过接口名.变量名访问;
  2. final:赋值后不可二次修改;
java 复制代码
interface USB{double VERSION=3.0;}
public class Test{
    public static void main(String[] args){
        System.out.println(USB.VERSION);
        USB.VERSION=2.0; // final常量不能修改,编译报错
    }
}
特性6:接口无构造方法、无静态代码块

构造方法用于实例化对象,接口不能创建对象,语法直接禁用构造器与静态代码块。

特性7:接口编译后同样生成.class字节码文件

虽然interface不是class,但编译后和普通类一致生成独立class文件,由JVM统一加载解析。

特性8:实现类未实现接口全部抽象方法 → 当前类必须定义为abstract抽象类

和抽象类继承规则保持统一,未完成全部方法实现则升级抽象类。

特性9:JDK8新增default、static方法,JDK9支持接口私有方法

基础学习阶段默认以JDK7规范为主,面试需区分不同JDK版本接口语法变动。

2.5 类单继承、多实现;接口支持多继承

Java类是单继承机制:一个类只能直接继承一个父类 ,但可以同时实现N个接口,弥补Java没有多继承的短板;接口和接口之间支持多继承extends,一次性合并多个父接口的抽象方法。

2.5.1 一个类继承单个父类+实现多个接口(项目最常用)

以动物能力为案例:父类Animal(is-a动物,抽取公共name属性),三个能力接口IFlying会飞、IRunning会跑、ISwimming会游泳(具备某项能力),猫、鱼、青蛙、鸭子按需实现接口:

java 复制代码
// 父类:动物,提取所有动物公共属性name
class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
    }
}
// 三个能力接口
interface IFlying {void fly();}
interface IRunning {void run();}
interface ISwimming {void swim();}

// 猫:是动物,具备奔跑能力
class Cat extends Animal implements IRunning {
    public Cat(String name) {super(name);}
    @Override
    public void run() {System.out.println(this.name + "正在用四条腿跑");}
}
// 鱼:是动物,具备游泳能力
class Fish extends Animal implements ISwimming {
    public Fish(String name) {super(name);}
    @Override
    public void swim() {System.out.println(this.name + "正在用尾巴游泳");}
}
// 青蛙:两栖动物,会跑+游泳,实现两个接口
class Frog extends Animal implements IRunning, ISwimming {
    public Frog(String name) {super(name);}
    @Override
    public void run() {System.out.println(this.name + "正在往前跳");}
    @Override
    public void swim() {System.out.println(this.name + "正在蹬腿游泳");}
}
// 鸭子:水陆空三栖,实现全部三个接口
class Duck extends Animal implements IRunning, ISwimming, IFlying {
    public Duck(String name) {super(name);}
    @Override public void fly() {System.out.println(this.name + "正在用翅膀飞");}
    @Override public void run() {System.out.println(this.name + "正在用两条腿跑");}
    @Override public void swim() {System.out.println(this.name + "正在漂在水上");}
}

多态落地:只关心能力,不在乎实体类型

java 复制代码
// 只要实现IRunning,无论动物还是机器人,都可以传入散步方法
public static void walk(IRunning running) {
    System.out.println("我带着伙伴去散步");
    running.run();
}
// 机器人不是动物,但是具备奔跑能力,同样可以参与散步
class Robot implements IRunning {
    private String name;
    public Robot(String name) {this.name = name;}
    @Override
    public void run() {System.out.println(this.name + "正在用轮子跑");}
}
//测试
Cat cat = new Cat("小猫");
Frog frog = new Frog("小青蛙");
Robot robot = new Robot("机器人");
walk(cat);
walk(frog);
walk(robot);

该设计是接口核心价值:面向接口编程,面向能力编程,代码高度解耦,拓展性极强,是框架设计最主流的设计思想。

2.5.2 接口多继承extends

一个子接口可以同时继承多个父接口,自动拥有所有父接口抽象方法,实现类需要实现全部父接口方法:

java 复制代码
interface IRunning {void run();}
interface ISwimming {void swim();}
// 两栖接口:一次性继承两个父接口
interface IAmphibious extends IRunning, ISwimming {}
// 实现两栖接口,必须实现run+swim两个方法
class Frog implements IAmphibious {
    @Override public void run() {}
    @Override public void swim() {}
}

2.6 JDK三大常用内置接口实战:Comparable、Comparator、Cloneable

2.6.1 Comparable(自然排序:内置比较,固定排序规则)

实体类实现Comparable接口,重写compareTo(Object o)在类内部定义唯一比较规则,规则写死无法灵活切换

返回值规则:当前对象大于参数对象返回正数、小于返回负数、相等返回0。

缺点:如需更换排序规则,必须修改实体类源码,违背开闭原则。

2.6.2 Comparator(外部比较器:灵活多规则排序)

不在实体类内部修改代码,单独新建比较器类实现Comparator接口,一套实体类可以创建N种比较规则(分数、姓名、年龄),随时切换,企业开发首选。

java 复制代码
class Student {
    public String name;
    public int score;
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
    @Override public String toString() {
        return "[" + this.name + ":" + this.score + "]";
    }
}
// 分数比较器
class ScoreComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.score-o2.score;
    }
}
// 姓名字典序比较器
class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
2.6.3 Cloneable克隆接口、浅拷贝与深拷贝详解

Object自带clone()对象克隆方法,类必须实现Cloneable接口才能合法调用clone(),否则抛出CloneNotSupportedException异常

  1. 浅拷贝:默认clone只复制对象本身,对象内部引用类型成员仅复制地址,新旧对象共用同一个引用对象,修改其中一个会同步影响另一个;
java 复制代码
class Money {public double m = 99.99;}
class Person implements Cloneable{
    public Money money = new Money();
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
//测试
Person p1 = new Person();
Person p2 = (Person)p1.clone();
p2.money.m = 13.6;
System.out.println(p1.money.m); //输出13.6,两个对象共用Money
  1. 深拷贝:手动在clone方法中new新的成员对象,断开引用共享,实现完全独立的对象拷贝。

2.7 抽象类与接口核心区别(面试高频考点)

对比维度 抽象类 abstract class 接口 interface
关键字 abstract class interface
构造方法 允许存在构造器,用于子类初始化父类 无构造方法,不能实例化
成员变量 修饰符任意(public/private/protected),可普通变量、常量 默认public static final常量,定义必须初始化
普通方法 可以包含任意普通实例方法、静态方法 JDK7全抽象;JDK8+支持default/static
抽象方法 abstract修饰,权限自定义 默认public abstract,权限不可修改
继承实现 类单继承:extends 一个抽象类 类多实现:implements 多个接口;接口多继承
设计语义 is-a(是什么事物,抽取共性属性+行为) has-a(具备某种功能、能力,定义行为规范)

选型口诀:多个子类有大量共同属性+通用方法 → 抽象类;只定义功能规范、不同类零散具备相同能力 → 接口

第三章 内部类全解:四大分类、访问规则、创建语法

3.1 内部类基础概念

定义在另一个类{}内部的类称为内部类,包裹它的类是外部类,是封装思想的拓展形式,把专属外部类使用的功能封装在类内部。

注意:两个类在同一个.java文件中平级定义,不属于内部类。

java 复制代码
public class OutClass {}
class B{} // OutClass和B平级,无内部类关系

编译特性:内部类编译后生成独立.class文件,命名规则:外部类名$内部类名.class

内部类分为四大类:静态内部类、实例(成员)内部类、局部内部类、匿名内部类,其中匿名内部类是日常开发使用最多的类型。

3.2 静态内部类(static修饰成员内部类)

  1. 定义位置:外部类成员位置、被static修饰;
  2. 访问权限:仅能直接访问外部类static静态成员,无法访问外部实例变量
  3. 对象创建:无需先创建外部类实例,直接外部类.内部类 对象=new 外部类.内部类();
java 复制代码
public class OutClass {
    public int a;          // 实例变量
    public static int b=10;// 静态变量
    // 静态内部类
    static class InnerClass{
        public void methodInner(){
            // a=100; 报错:不能访问非静态成员
            System.out.println(b);
        }
    }
    public static void main(String[] args) {
        OutClass.InnerClass inner = new OutClass.InnerClass();
        inner.methodInner();
    }
}

3.3 实例内部类(非static成员内部类)

  1. 定义:成员位置、无static修饰;
  2. 访问:直接访问外部类所有成员(任意权限private/public都能访问)
  3. 同名变量就近原则:优先内部类自身变量,外部类名.this.变量名访问外部同名属性;
  4. 创建对象:必须依托外部类实例,new 外部类().new 内部类()
java 复制代码
public class OutClass {
    public int c=100;
    class InnerClass{
        int c=200;
        public void test(){
            System.out.println(c); //200 优先内部自身
            System.out.println(OutClass.this.c);//100 指定访问外部类
        }
    }
    public static void main(String[] args) {
        OutClass out = new OutClass();
        OutClass.InnerClass in = out.new InnerClass();
        in.test();
    }
}

补充规则:外部类无法直接访问实例内部类成员,必须创建内部类对象后访问。

3.4 局部内部类(方法内定义)

  1. 定义:外部类方法体{}内部;
  2. 修饰限制:不能加public/private/static等访问修饰符;
  3. 使用范围:仅限当前方法内部,方法外无法创建使用,日常开发极少使用。
java 复制代码
public class OutClass {
    int a = 10;
    public void method(){
        //局部内部类
        class Inner{
            public void func(){
                System.out.println(a);
            }
        }
        // 仅本方法可用
        Inner inner = new Inner();
        inner.func();
    }
}

3.5 匿名内部类(开发最常用,无类名)

没有类名、定义的同时直接实例化,只能使用一次,用于快速实现接口/抽象类/普通父类

语法:new 父类/接口(){重写抽象方法};

java 复制代码
interface Greeting {void greet();}
public class Test {
    public static void main(String[] args) {
        // 匿名内部类:实现Greeting接口,直接创建对象
        Greeting greeting = new Greeting() {
            @Override
            public void greet() {
                System.out.println("Hello!");
            }
        };
        greeting.greet();
    }
}

硬性限制:一个匿名内部类只能继承一个父类 或 实现一个接口,不能同时继承类+实现接口,也是课后选择题考点。

第四章 Object顶层父类:所有Java类的祖宗类

4.1 Object基础定义

Java中所有类默认隐式extends Object,是整个类层级的顶层根类,任意引用类型都可以使用Object接收,是方法参数统一接收的最高类型。

java 复制代码
class Person{}
class Student{}
public class Test {
    // Object统一接收所有对象
    public static void func(Object obj){
        System.out.println(obj);
    }
    public static void main(String[] args) {
        func(new Person());
        func(new Student());
    }
}

Object内置11个原生方法,开发重点掌握toString()、equals()、hashCode()、clone()四个,wait/notify系列用于多线程。

4.2 toString()方法

默认源码实现:

java 复制代码
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

默认返回格式:类名@十六进制哈希地址,打印对象地址无业务意义;重写toString(),输出对象属性信息,方便日志打印与调试

4.3 equals()方法与==区分(重中之重)

  1. ==:基本数据类型比较数值;引用数据类型比较对象内存地址;
  2. Object原生equals()底层就是==,默认比较地址:
java 复制代码
public boolean equals(Object obj) {
    return (this == obj);
}

业务需求对比对象内容时,必须重写equals(),逐个对比成员属性值:

java 复制代码
class Person{
    private String name;
    private int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    @Override
    public boolean equals(Object obj) {
        if(obj==null) return false;
        if(this==obj) return true;
        if(!(obj instanceof Person)) return false;
        Person p = (Person)obj;
        return this.name.equals(p.name) && this.age==p.age;
    }
}

4.4 hashCode()哈希方法

  1. native本地方法,由C/C++底层实现,返回int类型哈希值;
  2. 开发强制规范:equals相等的两个对象,hashCode必须相等;equals不等,hashCode尽量不同
  3. 不重写hashCode时,同属性不同对象哈希值不同,重写后基于对象属性计算哈希值:
java 复制代码
@Override
public int hashCode() {
    return Objects.hash(name, age);
}

hashCode主要作用:配合哈希表(HashMap/HashSet)存储数据,普通业务不涉及集合时作用有限。

4.5 Object其他方法简要说明

  1. clone():对象克隆,需要实现Cloneable接口;
  2. getClass():反射获取对象运行时实际类型;
  3. wait()/notify()/notifyAll():多线程等待唤醒,线程同步核心方法;
  4. finalize():垃圾回收回调方法,JDK9已废弃。

第五章 课后习题详细解析

题目1 抽象类错误选项:BD

A.抽象类可以包含非抽象方法 ✔;B.抽象类可以被实例化 ❌;C.抽象类可以有构造方法✔;D.一个类可以继承多个抽象类❌(Java类单继承)

题目2 接口正确选项:B

A.接口所有方法必须抽象 ❌(JDK8有default/static普通方法);B.接口可以包含静态方法✔;C.接口可以有私有方法❌(JDK9才支持,基础阶段默认不行);D.一个类只能实现一个接口❌(多实现)

题目3 内部类错误选项:D

D错误:匿名内部类不能同时继承类+实现接口,只能二选一;ABC描述全部正确。

题目4 抽象类&接口正确:AC

A.抽象有构造、接口无构造✔;B.类不能实现抽象类,只能继承,类可以多实现接口❌;C.接口方法默认public,抽象类权限任意✔;D.抽象类可以无抽象方法❌。

结语

抽象类聚焦共性抽取、模板定义 ,接口聚焦能力规范、代码解耦,内部类用于精细化封装独有逻辑,Object是Java所有对象的顶层基准。四项语法相辅相成,共同构成Java面向对象多态体系的基石。

在实际项目分层开发、主流框架(Spring/MyBatis)源码中随处可见上述语法:框架大量使用接口定义规范、抽象类封装通用模板、匿名内部类实现回调处理、实体类成对重写equals+hashCode完成判重。吃透本文知识点,既能应对校招、社招Java面试高频提问,也能为后续集合、反射、框架学习筑牢底层基础。

感谢你的阅读!欢迎三连支持!

相关推荐
阿维的博客日记1 小时前
‘version‘ must be a constant version but is ‘${revision}‘
java·spring boot·后端
C+++Python1 小时前
C++ 常量全面讲解
java·开发语言·c++
程序员小羊!1 小时前
17 Maven
java·maven
C+-C资深大佬1 小时前
C++ 数字与字符串互转
java·c++·算法
陈猪的杰咪1 小时前
DeepSeek V4 中转方案全解析 | Flash 成本仅为 GPT 的 1/90
java·人工智能·gpt·spring
zlpzlpzyd1 小时前
spring boot 4.1发布
java·数据库·spring boot
无籽西瓜a1 小时前
Plan-and-Execute 里的 DAG 是怎么工作的
java·后端·ai·agent·dag
ch.ju1 小时前
Java Programming Chapter 4——The difference between overloading and overwriting.
java·开发语言