本文档整理 Java 面向对象编程的核心知识,包括类、继承、接口、多态、内部类等概念。
目录
1. 访问权限
Java 内建的访问权限包括 public、protected、private 和 package(默认)四种:
| 修饰符 | 同类 | 同包 | 子类 | 任意位置 |
|---|---|---|---|---|
| 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 面向抽象编程的本质
- 上层代码只定义规范
- 不需要子类即可实现业务逻辑
- 具体业务逻辑由子类实现,调用者不关心
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.class、Outer$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,适合用于固定集合的类型安全表示