1. 面向对象编程三大特性
1.1 封装
隐藏对象的属性和实现细节,仅对外公开访问方法,控制在程序中属性的读和写的访问级别。
封装基本要求
- 把所有的属性私有化。
- 对每个属性提供
getter和setter方法。 - 如果有一个带参的构造函数的话,那一定要写一个不带参的构造函数。
- 建议重写
toString方法,但这不是必须的。
1.2 继承
可以理解为,在一个现有类的基础之上,增加新的方法或重写已有方法,从而产生一个新类。
每一个类都是在继承。因为在 Java 中存在一个所有类的父类(基类、超类):java.lang.Object。
继承和权限
-
子类不能继承父类中访问权限为
private的成员变量和方法,也不能继承父类的构造方法。 -
子类可以重写父类的方法,及命名与父类同名的成员变量。
有时候我们会有这样的需求:我们需要将某些事物尽可能地对这个世界隐藏,但是仍然允许子类的成员来访问它们。这个时候就需要使用到 protected。
类成员访问修饰符与访问能力之间的关系:
| 类型 | private | 无修饰 | protected | public |
|---|---|---|---|---|
| 同一类 | 可访问 | 可访问 | 可访问 | 可访问 |
| 同一包中的子类 | 不可访问 | 可访问 | 可访问 | 可访问 |
| 同一包中的非子类 | 不可访问 | 可访问 | 可访问 | 可访问 |
| 不同包中的子类 | 不可访问 | 不可访问 | 可访问 | 可访问 |
| 不同包中的非子类 | 不可访问 | 不可访问 | 不可访问 | 可访问 |
1.3 Java中类的划分
Java 中类可分为以下三种:
- 普通类:使用
class定义且不含有抽象方法的类。 - 抽象类:使用
abstract class定义的类,它可以含有或不含有抽象方法。 - 接口:使用
interface定义的类。
上述三种类存在以下的继承规律:
- 普通类可以继承(
extends)普通类,可以继承(extends)抽象类,可以继承(implements)接口。 - 抽象类可以继承(
extends)普通类,可以继承(extends)抽象类,可以继承(implements)接口。 - 接口只能继承(
extends)接口。
各继承规律中的约束:
- 一个普通类或一个抽象类,要么继承一个普通类,要么继承一个抽象类,即所谓的单继承。
- 一个普通类或一个抽象类或一个接口,可以继承任意多个接口。
- 一个普通类继承一个抽象类后,必须实现这个抽象类中定义的所有抽象(
abstract)方法,否则就只能被定义为抽象类。 - 一个普通类继承一个接口后,必须实现这个接口中定义的所有方法,否则就只能被定义为抽象类。
- 抽象类继承抽象类,或者实现接口时,可以部分、全部或者完全不实现父类抽象类的抽象(
abstract)方法或父类接口中定义的方法。
1.4 多态
相同的事物,调用其相同的方法,参数也相同时,但表现的行为却不同。
继承是多态得以实现的基础。
绑定
将一个方法调用同这个方法所属的主体(也就是对象或类)关联起来,分前期绑定和后期绑定两种。
- 前期绑定:在程序运行之前进行绑定,由编译器和连接程序实现,又叫做静态绑定。比如
static方法和final方法,注意,这里也包括private方法,因为它是隐式final的。- 后期绑定:在运行时根据对象的类型进行绑定,由方法调用机制实现,因此又叫做动态绑定,或者运行时绑定。除了前期绑定外的所有方法都属于后期绑定。
多态就是在后期绑定这种机制上实现的。
多态给我们带来的好处是消除了类之间的耦合关系,使程序更容易扩展。
实现多态的三个必要条件
- 继承:在多态中必须存在有继承关系的子类和父类。
- 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
- 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。
2. 重载和重写
型构
指方法的组成结构,具体包括方法的名称和参数,涵盖参数的数量、类型以及出现的顺序,但是不包括方法的返回值类型,访问权限修饰符,以及 abstract、static、final 等修饰符。
重写(overriding)
指在继承情况下,子类中定义了与其父类中方法具有相同型构的新方法,就称为子类把父类的方法重写了。这是实现多态必须的步骤。
- Java子类不能重写父类的静态方法,但是子类可以重新定义父类的静态方法,并将父类静态方法屏蔽。可以使用父类名.静态方法的方式调用:
public class StaticParent {
public static int a = 0;
public static void printA() {
System.out.println("In Parent, a = " + a);
}
}
public class StaticSon extends StaticParent {
public static void main(String[] args) {
printA();
}
// @Override 错误: 不能使用 @Override 注释静态方法
public static void printA() {
System.out.println("In son a = " + a);
StaticParent.printA();
}
// 输出:
// In son a = 0
// In Parent, a = 0
}
- 构造器不能被 override(重写),但是可以 overload(重载)
- 如果⽗类⽅法访问修饰符为
private/final/static则⼦类就不能重写该⽅法,但是被static修饰 的⽅法能够被再次声明。 - 关于 重写的返回值类型:如果⽅法的返 回类型是void和基本数据类型,则返回值重写时不可修改。但是如果⽅法的返回值是引⽤类型, 重写时是可以返回该引⽤类型的⼦类的。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
重载(overloading)
指在同一个类中定义了一个以上具有相同名称,但是型构不同的方法。
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。