Java 面向对象知识总结

5 阅读6分钟

本文档整理 Java 面向对象编程的核心知识,包括类、继承、接口、多态、内部类等概念。

目录

  1. 访问权限
  2. 继承与转型
  3. 多态
  4. 抽象类
  5. 接口
  6. 静态字段与方法
  7. 内部类
  8. 枚举(enum)
  9. 要点总结

1. 访问权限

Java 内建的访问权限包括 publicprotectedprivatepackage(默认)四种:

修饰符同类同包子类任意位置
public
protected
private
package

说明private 字段子类无法访问;protected 可被子类及子类的子类访问。

子类不会继承父类的构造方法,子类默认的构造方法由编译器自动生成。


2. 继承与转型

继承是面向对象的核心特性之一,用于表达"is-a"关系。通过继承,子类可以复用父类的代码,同时可以扩展或修改父类的行为。

2.1 继承关系

  • 继承是 is 关系,组合是 has 关系
  • Java 只允许单继承,所有类的最终根类是 Object

2.2 向上转型

把子类型安全地变成更抽象的父类型,自动转型,无需强制转换。

2.3 向下转型

将父类类型强制转为子类类型,可能出错,需使用 instanceof 判断:

Person p = new Person();
System.out.println(p instanceof Person);   // true
System.out.println(p instanceof Student);  // false

Student s = new Student();
System.out.println(s instanceof Person);    // true
System.out.println(s instanceof Student);   // true

Student n = null;
System.out.println(n instanceof Student);    // false

instanceof 判断变量指向的实例是否是指定类型或其子类。引用为 null 时始终返回 false

Person p = new Student();
if (p instanceof Student) {
    Student s = (Student) p; // 转型安全
}

3. 多态

多态(Polymorphism) 是面向对象的三大特性之一(封装、继承、多态)。

Java 的实例方法调用基于运行时的实际类型(动态绑定),而非变量的声明类型。

多态:针对某类型的方法调用,其真正执行的方法取决于运行时期实际类型。

3.1 final

  • 修饰方法:不能被 override
  • 修饰类:不能被继承

4. 抽象类

抽象类是对一类事物的抽象,被设计成只能用于被继承,强迫子类实现其定义的抽象方法,否则编译报错。它定义了子类的"规范",确保子类必须实现某些方法。

abstract class Person {
    public abstract void run();
    public abstract String getName();
}
  • abstract 定义的方法是抽象方法,只有定义没有实现
  • 定义了抽象方法的类必须也是抽象类
  • 子类必须实现抽象方法,否则仍是抽象类

4.1 面向抽象编程的本质

  1. 上层代码只定义规范
  2. 不需要子类即可实现业务逻辑
  3. 具体业务逻辑由子类实现,调用者不关心

5. 接口

接口(Interface) 是比抽象类更抽象的"纯抽象接口",它只定义行为规范,不包含任何实现细节。当抽象类中没有实例字段且所有方法都是抽象方法时,可以改写为接口。

interface Person {
    void run();
    String getName();
}

5.1 特点

  • 接口是比抽象类更抽象的纯抽象接口,连字段都不能有
  • 接口方法默认是 public abstract
  • 一个类只能继承一个类,但可以实现多个接口

5.2 接口继承

一个接口可以继承另一个接口,相当于扩展接口方法。

5.3 继承关系设计

  • 公共逻辑放在 abstract class
  • 具体逻辑放到各个子类
  • 接口层次代表抽象程度,接口比抽象类更抽象

5.4 default 方法

接口新增方法时,如果定义为 default 方法,实现类不必全部修改:

interface Payment {
    void pay();
    default void refund() { } // 新增方法不必强制实现
}

default 方法和抽象类的普通方法不同:接口没有字段,default 方法无法访问实例字段,而抽象类的普通方法可以。

5.5 示例:多态应用

interface Payment {
    void pay();
}

class Alipay implements Payment {
    public void pay() {
        System.out.println("支付宝支付");
    }
}

class WechatPay implements Payment {
    public void pay() {
        System.out.println("微信支付");
    }
}

// 向上转型后,无需区分具体子类
List<Payment> list = new ArrayList<>();
list.add(new Alipay());
list.add(new WechatPay());

6. 静态字段与方法

静态成员(字段和方法)属于类本身,而非某个实例。所有实例共享同一份静态数据。

6.1 静态字段

  • 静态字段只有一个共享空间,所有实例共享
  • 修改任一实例的静态字段,效果对所有实例可见
  • 推荐用类名访问:ClassName.staticField

6.2 静态方法

  • 无需实例即可通过类名调用
  • 静态方法内无法访问 this 或实例字段,只能访问静态字段

6.3 接口的静态字段

接口可以有静态字段,但必须是 final 类型(编译器自动添加 public static final):

public interface Person {
    int MALE = 1;   // 相当于 public static final int MALE = 1;
    int FEMALE = 2;
}

7. 包

  • 包(package)解决命名冲突
  • 完整类名 = 包名.类名
  • 同一个包的类可以访问包作用域(默认权限)的成员
import other.package.ClassName;  // 导入其他类

8. 内部类

内部类是定义在类内部的类,它可以访问外部类的所有成员(包括 private)。Java 的内部类分为三种,各有用途。

8.1 Inner Class(成员内部类)

内部类实例不能单独存在,必须依附于外部类实例:

class Outer {
    private String name;

    class Inner {
        void hello() {
            System.out.println("Hello, " + Outer.this.name);
        }
    }
}

实例化方式

Outer outer = new Outer("Nested");
Outer.Inner inner = outer.new Inner();

编译后:Outer.classOuter$Inner.class

特点:

  • 隐含持有 Outer.this 实例
  • 可访问外部类的 private 字段和方法

8.2 Anonymous Class(匿名内部类)

不需要在外部类中明确声明,在方法内部通过匿名类定义:

void asyncHello() {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("Hello, " + Outer.this.name);
        }
    };
    new Thread(r).start();
}

编译后:Outer$1.class

匿名类也可继承自普通类

HashMap<String, String> map = new HashMap<>() {
    {
        put("A", "1");
        put("B", "2");
    }
};

8.3 Static Nested Class(静态内部类)

使用 static 修饰,不依附于外部类实例,是完全独立的类:

static class StaticNested {
    void hello() {
        System.out.println("Hello, " + Outer.NAME);
    }
}

实例化方式new Outer.StaticNested()

特点:

  • 无法引用 Outer.this
  • 可访问外部类的 private 静态字段和静态方法
  • 不能访问外部类的实例字段

8.4 三种内部类对比

类型是否依附外部类实例可访问 Outer.this可访问实例成员
Inner Class
Anonymous Class
Static Nested Class

8.5 典型应用:单例模式

class Singleton {
    private Singleton() {}

    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

外部类加载时 Holder 不会被加载,实现延迟加载,天然线程安全。


9. 枚举(enum)

枚举(Enumeration) 用于表示固定集合的类型,比使用常量更类型安全。枚举类本质上是一个特殊的类,继承自 java.lang.Enum

enum Weekday {
    SUN, MON, TUE, WED, THU, FRI, SAT;
}

9.1 特点

  • 枚举类继承自 java.lang.Enum,无法被继承
  • 只能定义枚举实例,无法通过 new 创建
  • 每个实例全局唯一
  • 适合用于 switch 语句

9.2 枚举类本质

public final class Weekday extends Enum {
    public static final Weekday SUN = new Weekday();
    public static final Weekday MON = new Weekday();
    // ...
    private Weekday() {}
}

9.3 常用方法

  • name():获取常量定义的字符串(推荐)
  • ordinal():返回常量定义的顺序(无实质意义)
  • toString():不推荐使用

9.4 枚举构造

枚举类可以有构造方法、字段和方法,构造方法必须声明为 private

public enum Color {
    RED("红色"), GREEN("绿色"), BLUE("蓝色");

    private final String ChineseName;

    Color(String name) {
        this.ChineseName = name;
    }
}

10. 要点总结

  • 访问权限public > protected > package > private
  • 转型:向上转型安全,向下转型需用 instanceof 判断
  • 多态:基于运行时实际类型的动态调用
  • 抽象类 vs 接口:抽象类可包含实例字段和具体方法,接口更抽象(Java 8 后可有 default 方法)
  • 内部类:Inner Class 和 Anonymous Class 必须依附外部类实例,Static Nested Class 独立存在
  • 枚举:特殊类,继承自 Enum,适合用于固定集合的类型安全表示