面向对象三大特征:封装、继承、多态,super关键字
【摘要】OO的核心思想:面向父类、抽象、接口编程;对扩展开放,对修改关闭;高内聚、低耦合。
前言
面向对象三大特征:封装、继承、多态;五大基本原则:单一职责原则(SRP)、开放封闭原则(OCP)、里氏替换原则(LSP)、依赖倒置原则(DIP)、接口隔离原则(ISP)。
封装[encapsulation]
封装简单的说就是该隐藏的隐藏,该公开的公开。优点如下:
- 提高代码的安全性。
- 提高代码的复用性。
- “高内聚”:封装细节,便于修改内部代码,提高可维护性。
- “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。
类的封装
- 属性尽可能地私有化。
但是为了外面的调用者要存取属性,我们必须对属性提供公开的存取方法。也就是get和set方法。
如:1
2
3
4
5
6
7public String getStuName(){
return this.stuName;
}
public void setStuName(String stuName){
this.stuName = stuName;
} - 对外的业务方法要公开。
涉及到访问修饰符的使用。
方法的封装
由于类的数据[属性]和功能[方法]是分开的,所以,我们可以有另一个策略来封装类的功能。
策略一:把类的属性、构造、存取方法以及业务方法全部封装。同一个类中,这种策略适合功能单一、业务简单的场景下。
如:要封装一个银行账户类:
1 | public class Account { |
策略二:把类的属性、构造、存取方法单独封装成一个实体类,它就是纯数据的载体,而针对这个数据的操作,也就是业务方法另外封装成一个类[业务类]。
1 | //实体类 |
很显然,策略二的扩展性更好。
继承[inheritance]
继承是一种能够让子类快速[获取父类]代码复用的机制。
在Java中,类只支持单继承,优点是结构简单,易于管理。
在java中,继承还有如下特点:
A.单继承。
B.传递性。
C.所有类都直接或者间接继承于java.lang.Object类。
如果自定义的类型没有显示地指定父类,则自动继承java.lang.Object类。
可以使用extends
关键字表达继承关系。
当A类继承B类时,则可以这么表达:
1 | public class B{ |
此时,我们可以说:
类A是类B的子类/派生类。
类B是类A的父类/超类[super class]。
何时使用继承呢?
1.使用集成时,两个类之间要满足IS A的关系。
2.只有当他们之间满足IS A的关系时,才应该使用继承关系否则,不要轻易使用继承。
如:Bird IS A Animals
Apple IS A Fruits
...
有了父子类后,累的属性该如何划分?
共性归父类、个性归子类。
如:
1 | public class Animals { |
注
:对象的编译时类型可以变化,但是,它的运行时类型永远不会改变,从对象创建时就已确定。
有了父子类后,创建对象的步骤升级为:总是按如下三步递归地创建父类对象
1.申请堆空间[本类对象]
2.给属性赋初始值[本类对象]
3.调用构造方法[本类对象]
多态[polymorphism]
具有相同类型的对象,调用同一个方法时,表现出不同的行为。但是,这要有如下前提:
A.要有继承关系
B.要有方法的重写[被调用的方法]
所谓方法的重写[override],是指子类中的方法声明与父类申明保持一致。可以体现在:
A.子类方法的访问控制修饰符必须大于或等于父类的。
B.子类方法的返回类型的上限是父类方法的返回类型。
C.方法名必须一样
D.参数列表必须一样
E.子类方法抛出
如:
1 | Animals a1 = new Dog(); |
- 对象的编译时类型决定了对象所能“看得见”的行为。
- 对象的运行时类型决定了对象的真正行为。
为什么此时对象的编译时类型要写Animals呢?
因为要用“统一”的类型来处理这些对象,而使用这些对象的父类类型是
一种既可以满足多态的要求又可以达到用户的解决方案。
因为要遵守如下OO的思想:
面向父类编程
面向接口编程
面向抽象编程
从编程的角度来理解的话,可以分为
1.对象的编译时类型尽可能的写父类
2.方法的参数尽可能地写父类
如:
1 | public void m(Dog d){ |
可改成:
1 | public void m(Animals a){ |
super关键字
- 在构造器中,用来调用父类的构造器。若是构造方法的第一行没有显式的
supper(...)
或者this(...)
,那么Java
默认都会调用super()
,含义是调用父类的无参构造方法。 - 表示指向父类对象的指针[引用]。
如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class A {
protected int index = 50;
public void f(){
System.out.println("A:"+index);
}
//...
}
public class B extends A {
private int index = 100;
//
public void f(){
super.f();//调用父类的普通方法
System.out.println("B:"+index);
//System.out.println("A:"+super.index);//调用父类的成员属性
}
结束语
~