On java 8 笔记——第一章 对象的概念
抽象
面向对象程序设计方法:
1. 万物皆对象。
2. 程序是一组对象,通过消息来传递告知彼此该做什么。
3. 每个对象都有自己的存储空间,可容纳其他对象。
4. 每个对象都有一种类型。
5. 同一类所有对象都能接收相同的消息。
更为简洁的描述:
一个对象具有自己的状态,行为和标识。这意味着对象有自己的内部数据(提供状态)、方法 (产生行为),并彼此区分(每个对象在内存中都有唯一的地址)。
接口
程序中使用基本关键字 class 来引入新的类型(class 和 type 通常可互换使用,有些人对它们进行了进一步区分,他们强调 type 决定了接口,而 class 是那个接口的一种特殊实现方式)。
创建好一个类(class)后,可根据情况生成许多对象(Object)。
那么如何利用对象完成真正有用的工作呢?
必须有一种办法能向对象发出请求,令其解决一些实际的问题。
我们向对象发出的请求是通过它的“接口”**(Interface)**定义的,对象的“类型”或“类”则规定了它的接口形式。“类型”与“接口”的对应关系是面向对象程序设计的基础。
下面让我们以电灯泡为例:
在这个例子中:
类型/类的名称是 Light
可向 Light 对象发出的请求包括 on、 off、brighten 、 dim。
Light lt = new Light()
通过声明一个引用,如 lt 和 new 关键字,我们创建了一个 Light 类型的对象,再用等号将其赋给引用。
lt.on();
为了向对象发送消息,我们使用句点符号 “.” 将 lt 和on 连接起来。
封装
研发程序员开发一个工具类,该工具类仅向应用程序员公开必要的内容,并隐藏内部实现的细节。这样可以有效地避免该工具类被错误的使用和更改,从而减少程序出错的可能。
Java 有三个显式关键字来设置类中的访问权限:
- public :公开:任何人都可以访问和使用该元素;
- private :私有:除了类本身和类内部的方法,外界无法直接访问该元素。private是类和调用者之间的屏障。任何试图访问私有成员的行为都会报编译时错误;
- protected :受保护:类似于 private ,区别是子类可以访问 protected的成员,但不能访问 private 成员;
- default :默认:如果不使用前面的三者,默认就是 default 访问权限。default 被称为包访问,因为该权限下的资源可以被同一包(库组件)中其他类的成员访问。
复用
代码和设计方案的复用性是面向对象程序设计的优点之一。
我们可以通过重复使用某个类的对象来达到这种复用性。同时,我们也可以将一个类的对象作为另一个类的成员变量使用。新的类可以是由任意数量和任意类型的其他对象构成。这里涉及到“组合”和“聚合”的概念:
- 组合(Composition)经常用来表示“拥有”关系(has-a relationship)。例如,“汽车拥有引擎”。
- 聚合(Aggregation)动态的组合(动态的拥有)。
上图中实心三角形指向“ Car ”表示 组合 的关系;如果是 聚合 关系,可以使用空心三角形。
继承
基类用基类表示。
继承类用继承类表示。
继承并不完全等价于克隆。在继承过程中,若原始类(正式名称叫作基类、超类或父类)发生了变化,修改过的“克隆”类(正式名称叫作继承类或者子类)也会反映出这种变化。
基类包含派生自它的类型之间共享的所有特征和行为。创建基类以表示思想的核心。
例如上图:
基类是“shape”,每个形状都有大小、颜色、位置等等,每个形状可以绘制、擦除、移动、着色等。
可以派生出(继承出)具体类型的形状——Circle、Square、Triangle等等——这些可以具有附加的特征和行为。
基类对象接收的所有消息也能被派生类对象接收,派生类与基类是相同的类型。
区分基类和派生类:
- 在派生类中添加新方法。这些新方法不是基类接口的一部分。这意味着基类不能满足你的所有需求。
- 改变现有基类方法的行为,这被称为覆盖 (overriding)(有人称之为重写)。要想覆盖一个方法,只需要在**派生类中重新定义这个方法**即可。
继承需要符合的关系是:is-a,基类更通用,派生类更具体。
关于继承更多内容详情见:对继承的理解
关于重写/覆盖更多内容详情见:重写的理解
“是一个”与“像是一个”的关系
在**派生类**添加了新的接口元素,从而扩展接口。基类无法访问派生类新添加的方法。
多态
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作
代码例子:
void doSomething(Shape shape) {
shape.erase();
// ...
shape.draw();
}
Circle circle = new Circle();
Triangle triangle = new Triangle();
Line line = new Line();
doSomething(circle);
doSomething(triangle);
doSomething(line);
传入不同的形状,都可以执行不同形状对应的函数。
多态的优点:
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的三个必要条件:
- 继承
- 重写
- 父类引用指向子类对象
例子:
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
输出:
吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠
多态的实现方式
方式一:重写
方式二:接口
方式三:抽象类和抽象方法