目录
一、多态
1、向上转型
1.1 定义
一个父类的引用指向一个子类的实例,通过父类引用调用父类和子类同名覆盖方法。此时,如果父类引用指向的子类对象不一样,调用这个重写的方法,表现得行为也不一样。
1.2 向上转型举例
例一: Dog dog = new Dog("旺旺",14);
Animal animal = dog;
例二: Animal animal = new Dog("旺旺",14);
向上转型之后,只能通过父类的引用访问父类自己特有的属性和方法,不能访问子类特有的方法和属性
1.3 代码实例
// 先创建父类Animal 和子类Dog
class Animal{
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Dog extends Animal{
public Dog(String name, int age) {
super(name, age);
}
}
// 向上转型并输出结果
public class test {
public static void main(String[] args) {
Dog dog = new Dog("旺旺",14);
Animal animal = dog;
System.out.println(animal.toString());
}
}
运行结果:
Dog{name='旺旺', age=14}
2、方法重写
2.1 满足规则
- 函数名称相同
- 函数参数列表相同
- 函数的返回值相同
2.2 注意事项
- 普通方法可以重写, static 修饰的静态方法不能重写
- 重写中子类的方法的访问权限不能低于父类的方法访问权限
- private 修饰的方法不可以重写
- 如果一个方法被 final 修饰称其为密封方法,也不可以重写
3、动态绑定
动态绑定又称运行时绑定,是多态的基础
通过父类引用调用父类和子类的同名覆盖方法,此时会发生动态绑定。绑定子类的同名函数
class Animal{
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("吃东西!");
}
}
class Dog extends Animal{
public Dog(String name, int age) {
super(name, age);
}
@Override //子类重写eat函数
public void eat() {
System.out.println("dog在吃!");
}
}
public class test {
public static void main(String[] args) {
Animal animal = new Dog("旺旺",14); //向上转型
animal.eat(); // 通过父类引用调用父类和子类同名覆盖方法
}
}
运行结果:
dog在吃!
4、向上转型发生的时机
4.1 直接赋值
Animal animal = new Dog("旺旺",14);
4.2 返回值
class Animal { //定义父类
public String name;
public int age;
public Animal(String name, int age) { //构造方法
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("吃东西!"); //普通方法
}
}
class Dog extends Animal { //定义子类
public Dog(String name, int age) {
super(name, age);
}
@Override //重写eat方法
public void eat() {
System.out.println("dog在吃!");
}
}
public class test1 {
public static Animal func(){ //定义返回值为Dog 类型的方法
Dog dog =new Dog("旺旺",14);
return dog;
}
public static void main(String[] args) {
Animal animal = func();
animal.eat();
}
}
运行结果:
dog在吃!
4.3 传参
class Animal {
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("吃东西!");
}
}
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(name+"在吃!");
}
}
class Cat extends Animal {
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(name+"在吃!");
}
}
public class test1 {
public static void func(Animal animal){
animal.eat();
}
public static void main(String[] args) {
Dog dog = new Dog("旺旺",14); //new哪个就调用哪个子类的eat函数
func(dog);
Cat cat = new Cat("喵喵",3);
func(cat);
}
}
运行结果:
旺旺在吃!
喵喵在吃!
5、super关键字
5.1 含义及用法
(1)含义: super 表示获取到父类实例的引用
(2)用法
- 使用了 super 来调用父类的构造器
public Bird(String name) { super(name); }
- 使用 super 来调用父类的普通方法
public class Bird extends Animal { public Bird(String name) { super(name); } @Override public void eat(String food) { // 修改代码 , 让子调用父类的接口 . super.eat(food); } }
5.2 super关键字与this关键字区别
区别 | this | super | |
1 | 概念 | 访问本类中的属性和方法 | 由子类访问父类的属性和方法 |
2 | 查找范围 | 先查找本类,本类没有则调用父类 | 直接调用父类 |
3 | 特殊 | 表示当前对象 | 无 |
6、多态的好处
- 类调用者对类的使用成本进一步降低
- 能够降低代码的“圈复杂度”,即避免使用大量的 if-else
- 可扩展能力强
二、抽象类
1、语法规则
抽象方法:该方法没有具体的实现,使用abstract修饰
抽象类:包含抽象方法的类称为抽象类
abstract class 类名 { abstract public void 方法名(); }
2、注意事项
(1)抽象类不能直接实例化(即不能new对象)
(2)抽象方法不能是 private 和 final 修饰的
(3)抽象类中可以包含其他的非抽象方法, 也可以包含字段. 这个非抽象方法和普通方法的规则都是一样的, 可以被重写, 也可以被子类直接调用
(4)如果一个普通类继承了抽象类,则普通类需要重写抽象类中的抽象方法
(5)一个抽象类A继承了另一个抽象类B,抽象类A中可以不重写抽象类B中的抽象方法。但是一旦抽象类A被继承后,继承的子类需要重写抽象类A和抽象类B中的所有抽象方法。
3、抽象类作用
抽象类存在的最大意义就是为了被继承
三、接口
1、语法规则
interface 接口名 { //定义接口 方法 属性 } class 类名 implements 接口名{ //实现接口 }
- 接口名一般以 I 开头
- 接口中的成员变量默认类型为: public static final
- 接口中的方法一定是抽象方法, 因此可以省略 abstract
- 接口中的方法一定是 public, 因此可以省略 public
- 使用 implements 继承接口 . 此时表达的含义不再是 " 扩展 ", 而是 " 实现 "
- 接口不能单独被实例化
2、实现多个接口
定义一组接口, 分别表示 "会飞的", "会跑的", "会游泳的",再定义青蛙类,因为青蛙, 既能跑, 又能游,因此青蛙类需实现两个接口。
interface IFlying {
void fly();
}
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
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 + "正在蹬腿游泳");
}
}
IDEA 中使用 ctrl + i 快速实现接口
3、接口间的继承
接口可以继承一个接口, 达到复用的效果. 使用 extends 关键字
4、接口和抽象类对比
区别 | 抽象类 | 接口 | |
1 | 结构组成 | 普通类+抽象方法 | 抽象方法+全局常量 |
2 | 权限 | 各种权限 | public |
3 | 子类使用 | extends关键字 | implements关键字 |
4 | 关系 | 一个抽象类可以实现若干接口 | 接口不能继承抽象类,但是接口可以使用关键字extends关键字实现多个父接口 |
5 | 子类限制 | 一个子类只能继承一个抽象类 | 一个子类可以实现多个接口 |