Java面向对象基础(二)
2026/6/5 8:45:58 网站建设 项目流程

Java 面向对象基础(二)

作者:没有四次元口袋的蓝胖
日期:2026-06-04
标签:Java, 面向对象, 继承, super, 重写, 多态


一、继承

1.1 什么是继承?

继承是子类复用父类属性和行为的机制,体现“is-a”关系。

classAnimal{Stringname;publicvoideat(){System.out.println(name+"在吃东西");}}classDogextendsAnimal{publicvoidbark(){System.out.println(name+"在汪汪叫");}}
Dogd=newDog();d.name="旺财";d.eat();// 继承自 Animald.bark();// Dog 自己的

1.2 继承的特点

特点说明
单继承一个类只能有一个直接父类(Java 不支持多继承)
多层继承A → B → C,可以形成继承链
所有类根没有显式继承时,默认继承java.lang.Object
子类获得父类非 private 的属性和方法
子类不可获父类的构造方法、private 成员

1.3 继承中的访问权限

子类能访问的父类成员: ✅ public → 哪里都能用 ✅ protected → 同包 + 不同包子类 ✅ 缺省(default) → 同包 ❌ private → 只有父类自己能用(但可以通过 public/protected 的 getter 间接访问)

1.4 什么时候用继承?

is-a 关系才用继承,has-a 关系用组合。

✅ Dog is an Animal → 继承(狗是动物) ✅ Cat is an Animal → 继承(猫是动物) ❌ Car has a Wheel → 组合,不是继承(车有轮胎) ❌ Student has a Book → 组合,不是继承(学生有书)

你可以说 “狗是动物”、“猫是动物”,但是不能说“车是轮胎”“学生是书”,不然就会出现“给汽车充气”、“获取学生价格”这样不合逻辑的情况。


二、super 关键字

2.1 super 是什么?

super代表父类的引用,用于在子类中访问父类的成员。

2.2 三种用法

用法 1:访问父类成员变量

当子类和父类有同名变量时,用super区分:

classAnimal{Stringname="动物";}classDogextendsAnimal{Stringname="狗";publicvoidshow(){System.out.println(name);// 狗(子类)System.out.println(super.name);// 动物(父类)}}
用法 2:调用父类成员方法
classAnimal{publicvoideat(){System.out.println("动物在吃东西");}}classDogextendsAnimal{@Overridepublicvoideat(){super.eat();// 先调用父类版本System.out.println("狗在啃骨头");}}newDog().eat();// 动物在吃东西// 狗在啃骨头
用法 3:调用父类构造方法
classAnimal{Stringname;publicAnimal(Stringname){this.name=name;}}classDogextendsAnimal{Stringbreed;publicDog(Stringname,Stringbreed){super(name);// 调用父类构造,必须放在第一行this.breed=breed;}}

2.3 super vs this

对比superthis
代表父类引用当前对象引用
访问成员super.变量/super.方法()this.变量/this.方法()
调用构造super(...)在子类构造第一行this(...)在构造第一行
互斥super()this()不能同时出现在一个构造方法中同左

2.4 子类构造的隐式 super()

classAnimal{publicAnimal(){System.out.println("Animal 构造");}}classDogextendsAnimal{publicDog(){super();// 即使不写,编译器也会自动加上System.out.println("Dog 构造");}}newDog();// Animal 构造// Dog 构造

⚠️ 如果父类没有无参构造,子类必须显式用super(...)调用父类有参构造,否则编译报错。


三、方法重写(Override)

3.1 什么是重写?

子类对父类的方法重新实现,使同一方法在不同子类中表现不同行为。

3.2 重写规则

规则说明
方法名必须相同
参数列表必须相同
返回值类型相同,或是父类返回值类型的子类(协变返回)
访问权限不能比父类更严格(可以更宽)
异常不能抛出比父类更多的受检异常
private/static/final不能被重写

权限放宽方向:private→ 缺省 →protectedpublic

classAnimal{publicObjectgetInfo(){return"动物信息";}}classDogextendsAnimal{@OverridepublicStringgetInfo(){return"狗的信息";}// ✅ String 是 Object 的子类(协变返回)}

3.3 @Override 注解

强烈建议每次重写都加上@Override,让编译器帮你检查:

classDogextendsAnimal{@Overridepublicvoideat(){}// ✅ 正确重写@Overridepublicvoideet(){}// ❌ 编译报错,父类没有这个方法,说明你拼错了}

3.4 重写 vs 重载(完整对比)

对比重载(Overload)重写(Override)
发生位置同一个类子类与父类
方法名相同相同
参数列表必须不同必须相同
返回值无关相同或子类
访问权限无关不能更严格
关系编译时多态运行时多态

四、多态

4.1 什么是多态?

同一个引用类型,调用同一个方法,表现出不同的行为。

核心前提:

  1. 有继承 / 实现关系
  2. 有方法重写
  3. 父类引用指向子类对象

4.2 基本用法

classAnimal{publicvoidspeak(){System.out.println("动物叫");}}classDogextendsAnimal{@Overridepublicvoidspeak(){System.out.println("汪汪汪");}}classCatextendsAnimal{@Overridepublicvoidspeak(){System.out.println("喵喵喵");}}
Animala1=newDog();// 父类引用 → 子类对象(向上转型)Animala2=newCat();a1.speak();// 汪汪汪 ← 运行时看实际对象类型a2.speak();// 喵喵喵 ← 运行时看实际对象类型

编译看左边,运行看右边——编译时检查引用类型有没有这个方法,运行时执行实际对象的重写版本。

4.3 向上转型与向下转型

向上转型(自动,安全)
Animala=newDog();// 子类 → 父类,自动转型a.speak();// 汪汪汪(多态生效)// a.bark(); // ❌ 编译报错,Animal 没有 bark()

向上转型后,只能调用父类中声明的方法,不能调用子类特有的方法。

向下转型(强制,需谨慎)
Animala=newDog();Dogd=(Dog)a;// 强制向下转型d.bark();// ✅ 现在可以调用了Catc=(Cat)a;// ❌ 运行时 ClassCastException!a 实际是 Dog
instanceof 判断(安全转型的保障)
Animala=newDog();if(ainstanceofDog){Dogd=(Dog)a;d.bark();}elseif(ainstanceofCat){Catc=(Cat)a;c.catchMouse();}

4.4 多态的实际应用

场景:方法参数用父类类型,兼容所有子类
classOwner{publicvoidfeed(Animalanimal){// 任何 Animal 子类都能传animal.speak();System.out.println("喂食完成");}}Ownerowner=newOwner();owner.feed(newDog());// 汪汪汪 → 喂食完成owner.feed(newCat());// 喵喵喵 → 喂食完成

不用多态的话,你要写feed(Dog d)feed(Cat c)……每加一种动物就加一个方法。多态一个方法搞定。

4.5 多态中成员变量没有多态效果

classAnimal{Stringname="动物";}classDogextendsAnimal{Stringname="狗";}Animala=newDog();System.out.println(a.name);// 动物 ← 成员变量看左边(引用类型)// 多态只对方法有效,变量没有多态

五、常见坑与面试考点

坑 1:父类没有无参构造,子类编译报错

classAnimal{publicAnimal(Stringname){}// 只有有参构造,无参构造没了}classDogextendsAnimal{publicDog(){}// ❌ 编译报错!隐式 super() 找不到无参构造publicDog(){super("默认");}// ✅ 显式调用父类有参构造}

坑 2:重写时缩小了访问权限

classAnimal{publicvoideat(){}}classDogextendsAnimal{@Overridevoideat(){}// ❌ 从 public 缩小到 default,编译报错}

坑 3:类初始化顺序(经典面试题)

classParent{static{System.out.println("1. 父类静态代码块");}{System.out.println("2. 父类实例代码块");}publicParent(){System.out.println("3. 父类构造方法");}}classChildextendsParent{static{System.out.println("4. 子类静态代码块");}{System.out.println("5. 子类实例代码块");}publicChild(){System.out.println("6. 子类构造方法");}}newChild();// 输出顺序:1 → 4 → 2 → 3 → 5 → 6

口诀:父类静态 → 子类静态 → 父类实例/构造 → 子类实例/构造


六、思维导图速览

面向对象进阶(二)—— 继承与多态 ├── 继承 │ ├── is-a 关系,单继承 │ ├── 子类获得父类非 private 成员 │ └── 所有类默认继承 Object ├── super 关键字 │ ├── 访问父类成员(super.变量 / super.方法()) │ ├── 调用父类构造(super(),必须在第一行) │ └── vs this 对比 ├── 方法重写(Override) │ ├── 规则:方法名/参数相同,权限不能更严 │ ├── @Override 注解(强烈建议) │ └── vs 重载(Overload)完整对比 └── 多态 ├── 编译看左边,运行看右边 ├── 向上转型(自动)/ 向下转型(强制 + instanceof) ├── 实际应用:方法参数用父类类型 └── 成员变量没有多态效果

写在最后

  1. 多态是重中之重——理解"编译看左、运行看右"是打开 Java 面向对象大门的钥匙,结合内存模型想几遍就通了。
  2. super 三种用法要熟练,尤其是super()调用父类构造。
  3. 重写 vs 重载现在就分清楚,后面学泛型会更晕,趁早搞明白。
  4. 初始化顺序口诀记住,面试手写一遍验证。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询