面向对象:封装,继承,多态的艺术
SryYa Three

面向对象

面向对象是什么?和面向过程有什么区别?

面向过程(Procedure Oriented) :

核心思想: 自顶向下,逐步细化。将问题拆解成一个个函数(动作),然后按顺序执行。

举例: 比如我想把大象装进冰箱。

面向过程思考的是:“第一步怎么做,第二步怎么做?“

所以面向过程会写出开冰箱门()放入大象()关冰箱门()一系列函数。 这些函数是零散的,不聚合的。

缺点: 当系统变大之后(比如我想放河马,放老虎,换个箱子当容器),由于这些步骤之间的耦合度很高,牵一发而动全身,对扩展和维护是及其不好的。

面向对象(Object Oriented):

核心思想: 世界是由对象组成的。我们将数据和行为封装在一起,通过对象之间的交互来解决问题。

举例: 依旧是我想把大象装进冰箱。

面向对象思考的是:”这件事涉及哪些角色?它们各有什么功能?”

所以面向对象会定义出一个个对象class 冰箱(){属性:颜色,大小;行为:开门(),关门()}class 大象(){属性:体积,重量;行为:走路()}
。执行时,冰箱执行开门,大象执行走路,冰箱执行关门。这样就把冰箱和大象解耦了,以后我们想换个动物,换个容器,只需要改动一处就行了。

缺点:虽然提高了代码复用性可维护性扩展性,但它并非完美无缺。面向对象为了实现”分层解耦”
,会让代码变得越来越臃肿,性能开销和系统复杂度也越来越高。就如很多人诟病着Java的迂腐:”为了吃一个鸡蛋,造了一个养鸡场。这种”千斤拨四两”的问题确实是面向对象不得不面对的。


封装、继承和多态

Java 面向对象三大特性的核心:

封装(Encapsulation)

继承(Inheritance)

多态(Polymorphism)

封装(Encapsulation)

对面展示细节,对外暴露接口。

在一个类里,属性是私有的(private),但提供公开的方法(public method)访问。

现在有User 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//不封装写法
class User {
public String name;
public int age;
}
//外部随便修改
User user = new User();
user.age = -100;
//数据不够安全
-------------------------------------
//封装写法
class User {
//属性私有
private String name;
private int age;
//提供getter setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
//还可以加逻辑控制
if(age < 0){
System.out.println("年龄不能小于0");
return;
}
this.age = age;
}
}
//通过提供的public方法调用
User user = new User();
user.setName("SryYa");
String name = user.getName();
int age = user.getAge();
System.out.println(name);
System.out.println(age);
//输出
SryYa
18

继承(Inheritance)

子类可以拥有父类的属性和方法。

形式:

1
class 子类 extends 父类

先定义父类:

1
2
3
4
5
6
7
8
9
10
11
class Car{
public void drive(){
System.out.println("正在行驶");
}
public void refuel(){
System.out.println("正在加能源");
}
public void playMusic(){
System.out.println("正在放歌");
}
}

子类:

1
2
3
4
5
6
class Tesla extends Car{
//子类自己的方法
public void playMusic(){
System.out.println("正在放歌");
}
}

使用:

1
2
3
4
5
6
7
8
9
public class Test {
public static void main(String[] args) {

Tesla tesla = new Tesla();

tesla.drive(); //继承父类方法
tesla.playMusic(); //自己的方法
}
}

运行结果:

1
2
正在行驶
正在放歌

子类Tesla通过extends拥有了父类Car的方法,这就是继承。

方法重写(Override)

子类可以重写父类方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//在上面的例子中,Tesla是电车,不能够加油,我们想给它充电该怎么办呢?可以重写加油的方法。
class Car{
public void refuel(){
System.out.println("正在加油");
}
}

class Tesla extends Car{
@override
//重写父类同名方法
public void refuel(){
System.out.println("正在充电");
}
}

这就是方法重写


多态(Polymorphism)

同一个方法,不同对象表现不同。

多态成立有三个条件:

  1. 继承
  2. 方法重写
  3. 父类引用指向子类对象

父类:

1
2
3
4
5
class Car{
public void refuel(){
System.out.println("正在加能源");
}
}

子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Tesla extends Car{
@Override
public void refuel(){
System.out.println("Tesla正在充电");
}
}

class Maybach extends Car{
@Override
public void refuel(){
System.out.println("Maybach正在加油");
}
}

使用:

1
2
3
4
5
6
7
8
public class Test {
public static void main(String[] args) {
Car tesla = new Tesla();
Car maybach = new Maybach();
tesla.refuel();
maybach.refuel();
}
}

输出:

1
2
Tesla正在充电
Maybach正在加油

注意:

1
2
Car tesla = new Tesla();
Car maybach = new Maybach();

变量类型使用的是父类Car,实际对象是Tesla/Maybach

使用时再决定具体调用哪个类。

这就是运行时多态(动态绑定)


方法重载(Overloading) VS 方法重写(Overriding)

运行时多态,当然也有编译时多态。它就是方法重载(Overloading)

方法重载的表现:

同一个方法,不同的参数,表现不同的形式。

1
2
3
4
5
6
7
8
9
class Test {
//传入
void print(int a){
System.out.println("打印int型变量");
}
void print(String a){
System.out.println("打印String型变量");
}
}

可以看到,同一个方法print,传入的参数不同,执行的代码也就不同。

课后问题:

下面的代码如果执行print(1),会发生什么呢?

1
2
3
4
5
6
void print(int a){
System.out.println("打印int型变量");
}
void print(long a){
System.out.println("打印long型变量");
}

总结

我们的目标是高内聚,低耦合。

面向对象(Object Oriented Programming) 是一种 以对象为中心的编程思想

核心思想只有一句话:

把现实世界的事物抽象成对象,通过对象之间的协作完成程序功能。

三大特性:

  • 封装,通过访问控制符(public,private)隐藏对象内部实现细节,只暴露必要接口,提高安全性
  • 继承,子类可以继承(extends)父类的属性和方法,实现代码复用
  • 多态同一方法在不同对象上表现出不同的行为,提高程序扩展性

面向对象核心的哲学是万物皆对象,用对象来模拟现实世界,每个人负责不同事情,让系统像社会一样协作运行。

由 Hexo 驱动 & 主题 Keep
总字数 28.1k 访客数 访问量