Java面向对象
Java 面向对象的核心是"类封装数据与行为、继承复用代码、多态让同一接口不同实现、接口定义契约"四条主线。面向对象不是语法堆砌,而是围绕"如何组织代码让变化可控"的工程方法论:封装隐藏实现细节,继承与接口表达"是什么/能做什么",多态让调用方依赖抽象而非具体类。理解这四条主线,就理解了 Java 一半的语法设计动机。
类与对象
类是模板(定义属性和方法),对象是模板的实例(具体的内存载体)。类定义成员变量(状态)、方法(行为)、构造器(初始化):
public class User {
private String name; // 成员变量:对象状态
private int age;
public User(String name, int age) { // 构造器:创建对象时初始化
this.name = name;
this.age = age;
}
public String getName() { return name; } // 方法:对象行为
}构造器的规则:与类同名、无返回类型;不写构造器时编译器生成无参构造器,但写了任意构造器后无参构造器不再自动生成——这是"为什么我 new 不了"的常见原因。
封装
封装把成员变量设为 private,通过 public 方法访问,好处是内部实现可以随意改,外部调用不受影响(如把 name 从 String 换成 StringBuilder 存,getName() 签名不变):
public class Account {
private double balance; // 外部不能直接改
public void deposit(double amt) {
if (amt <= 0) throw new IllegalArgumentException("金额必须为正");
balance += amt; // 校验逻辑收在内部
}
}继承
继承表达 "is-a" 关系:子类复用父类的字段与方法,并可覆写(override)父类方法。Java 是单继承(一个类只能有一个父类),用 extends 声明:
public class Animal {
public void speak() { System.out.println("动物叫"); }
}
public class Dog extends Animal {
@Override
public void speak() { System.out.println("汪汪"); } // 覆写
}构造顺序与 super
子类构造器第一行必须调用父类构造器(super(...),不写则默认调无参)。父类只有带参构造器时,子类必须显式 super(参数),否则编译错误。覆写的方法在父类构造器里被调用时,实际执行的是子类版本(构造期间的多态陷阱,尽量避免)。
多态
多态 = "编译看左边,运行看右边":用父类/接口类型引用子类对象,调用方法时实际执行子类版本。多态的价值是让代码面向抽象编程——新增一种子类时,调用方代码不用改:
Animal a = new Dog();
a.speak(); // 输出"汪汪"(运行期动态绑定)
// 多态的应用:参数接收任意 Animal 子类
public void letItSpeak(Animal animal) { animal.speak(); }多态成立的前提是 继承/实现 + 方法覆写。没有覆写,父类引用调的就是父类方法。
接口与抽象类
接口定义"能做什么"的契约(方法签名集合),抽象类提供"部分实现"的骨架。二者选型依据是"是否有可复用的通用实现":
| 维度 | 接口 interface | 抽象类 abstract class |
|---|---|---|
| 方法 | JDK8+ 可有 default/static 方法,其余纯抽象 | 可有抽象方法 + 具体方法 |
| 字段 | 只能是 public static final 常量 | 普通成员变量 |
| 继承 | 可多实现(一个类实现多个接口) | 单继承(一个类只能继承一个抽象类) |
| 语义 | "能做什么"(能力契约) | "是什么"(骨架复用) |
public interface Flyable {
void fly(); // 抽象方法:实现类必须实现
default void brake() { } // 默认方法:可选覆写
}
public abstract class Bird {
protected String name;
public abstract void sing(); // 抽象方法:子类必须实现
public void breathe() { } // 具体方法:子类直接复用
}选型口诀
优先接口(多实现、解耦调用方),需要共享字段或部分实现时用抽象类。经典组合:抽象类实现接口(模板方法模式),比如 AbstractList implements List。Java 8 的 lambda 本质也是接口的匿名实现(函数式接口)。
重载与覆写
| 概念 | 条件 | 目的 |
|---|---|---|
| 重载(Overload) | 同类中方法名相同、参数列表不同 | 提供多种调用形式 |
| 覆写(Override) | 子类方法签名与父类一致 | 改变父类行为 |
// 重载:同名不同参
public void print(String s) { }
public void print(int n) { }
// 覆写:必须 @Override 标注(编译器检查签名)
@Override
public void speak() { }覆写注意点:方法访问权限不能更严格(父类 public 子类不能 private)、异常不能更宽(父类抛 IOException,子类不能抛 Exception)、static/private/final 方法不能被覆写。
Object 与常见方法
所有类隐式继承 Object,几个方法需要理解默认行为:
| 方法 | 默认行为 | 何时覆写 |
|---|---|---|
equals() | 引用相等(==) | 需要值相等比较时(同时覆写 hashCode) |
hashCode() | 基于内存地址 | 与 equals 一致(equals 相等则 hashCode 必相等) |
toString() | 类名@hashCode | 需要可读的字符串表示 |
clone() | 浅拷贝 | 需要深拷贝时 |
equals 与 hashCode 一致性
放入 HashSet/HashMap 的类必须同时覆写 equals 与 hashCode:equals 相等的两个对象 hashCode 必须相等,否则集合判重失效(同一逻辑对象能存两份)。详见 Java集合 的 Set 章节。
面向对象与 Java类型系统 的类语义、Java内部类 的嵌套组织、Java8新特性 的 lambda/默认方法、反射机制 的运行时类型操作共同构成 Java 语言核心。