面向对象编程的组合、多态、抽象类的基本介绍(一)

简介: 面向对象编程的组合、多态、抽象类的基本介绍

面向对象

组合

和继承类似,组合也是表达类之家关系的方式,也是能够达到代码冲用的效果

例如:

组合并没有涉及到特殊的语法(诸如extends关键字),仅仅是将一个类的实例作为另一个类的字段,这是我们设计类的一种常用的方式之一

组合表示is-a语义

在刚才的例子中我们可以理解成一个学校“包含”若干学生和教师

继承表示has-a语义

在上面的“动物和猫”的例子中,也可以理解成猫也“是”一种动物

多态

向上转型

在上篇文章当中我们写了如下的代码

Bird bird = new Bird("圆圆");

这个代码也可以写成这样子

Animal bird2 = new Bird("圆圆");

此时bird2是一个父类(Animal)的引用,指向了一个子类(Bird)的实例,这种写法为向上转型

为啥叫“向上转型”?

在面向对象程序设计中,针对一些复杂的场景(很多类,很复杂的继承关系),程序员会画一种UML图来表示类之间的关系,此时父类通常画在子类的上方,我们就称之为“向上转型”,表示往父类的方向转,

注意:关于UML图的的规则我们不详细讨论,有兴趣的伙伴可以自己看看

向上转型发生的时机:

  • 直接赋值
  • 方法传参
  • 方法返回
    直接赋值的方式就是如上所示,另外两种方式和直接赋值没有本质区别

方法传参

public class Test {
  public static void feed(Animal animal){
    animal.eat("谷子");
  }
  public static void main(String[] args) {
    Bird bird = new Bird("圆圆");
    feed(bird);
  }
}
//执行结果
//圆圆正在吃谷子

此时形参animal的类型是Animal(基类),实际上对应到Bird(父类)的实例

方法返回

public class Test { 
  public static void main(String[] args) { 
    Animal animal = findMyAnimal(); 
  } 
  public static Animal findMyAnimal() { 
    Bird bird = new Bird("圆圆"); 
    return bird; 
  } 
}

此时findMyAnimal返回的是一个Animal类型的的引用,但是实际上对应到Bird的实例

动态绑定

当子类和父类中出现同名方法的时候,再去调用会出现什么情况?

class Animal {
    String name;
    public Animal(String name) {
        this.name = name;
    }
    public void eat(String food) {
        System.out.println("我是一只小动物");
        System.out.println(this.name + "正在吃" + food);
    }
}
class Bird extends Animal {
    public Bird(String name) {
        super(name);
    }
    public void eat(String food) {
        System.out.println("我是一只小鸟");
        System.out.println(this.name + "正在吃" + food);
    }
}
public class Main {
    public static void main(String[] args) {
        Animal animal = new Animal("圆圆");
        animal.eat("谷子");
        Animal animal2 = new Bird("扁扁");
        animal2.eat("谷子");
    }
}

运行结果:

此时我们发现:

  • animal1animal2虽然都是Animal类型的引用,但是animal1指向了Animal类型的实例,animal2指向了Bird类型的实例
  • 针对animal1animal2分别调用了eat方法,发现animal1.eat实际调用了父类的方法,而animal2.eat实际调用了子类的方法

方法重写

针对刚才的eat方法来说

子类实现父类的同名方法,并且参数的类型和个数完全相同,这种情况成为覆写/重写/覆盖(Override)

关于重写的注意事项

1.重写和重载完全不一样,不要混淆

2.普通的方法也可以重写,static修饰的静态方法不能重写

3.重写中子类的方法的访问权限不能低于父类的方法访问权限

4.重写的方法返回值类型不一定和父类的方法相同(但是建议写成相同,特殊情况除外)

有了这个注解能帮助我们进行一些合法性校验,例如不小心将名字拼错了(比如写成aet),那么此时编译器就会发现父类中没有aet方法,就会编译错误显示无法构成重写

小结:重载和重写的区别

体会动态绑定和方法重写

上面的动态绑定和方法重写使用的相同的代码示例

事实上,方法重写是Java语法层次上的规则,而动态绑定是方法重写这个语法规则的底层实现,两者本质上描述的是相同的事情,只是侧重点不同


相关文章
|
Linux 开发者
交叉编译工具链的下载与安装
交叉编译工具链的下载与安装
2719 1
|
Linux 编译器 C语言
深入理解Linux中的`as`命令:汇编器之旅
`as`命令是Linux下的GNU汇编器,用于将汇编语言源码(.s或.S)转化为机器码目标文件(.o)。它是GNU Binutils的一部分,在编译流程中扮演重要角色,尤其在底层编程和硬件交互时。基本用法是`as -o outputfile inputfile`。选项如`-g`添加调试信息,`-I`指定包含文件路径。通常与编译器如`gcc`配合使用,提供对计算机工作原理和操作系统底层的深入理解。学习汇编语言能增强编程和系统理解能力。
|
Ubuntu 安全 网络协议
|
开发工具
教你如何将WSL系统更换国内源?+固定路径+国内镜像源+详细教程
教你如何将WSL系统更换国内源?+固定路径+国内镜像源+详细教程
18357 2
|
NoSQL Linux 网络安全
关于Redis的远程连接 Connection: Disconnect on error 问题
关于Redis的远程连接 Connection: Disconnect on error 问题
|
Oracle 关系型数据库 MySQL
Mysql date_to_str()函数 日期格式化详细解析
Mysql date_to_str()函数 日期格式化详细解析
389 0
linux系统Give root password for maintenance解决办法
linux 系统Give root password for maintenance 问题的解决方法 ,希望能帮上朋友们!方法一:GIVE root password for maintenance (or type control-D to continue)Login incor...
15416 0