面向对象三大特性
继承,封装,多态
1. 继承
1.1 作用
1.代码复用,更加容易实现类的扩展
2.方便对事务建模
1.2 继承的实现
extends
1.3 继承使用要点
1 、 父类也称作超类、基类。子类:派生类等。
2 、Java中只有单继承,没有像c++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。
3 、 Java中类没有多继承,接口有多继承。
4 、子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),但不见得都可以直接访问(比如,父类私有的属性和方法)。
5 、 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object 。
1.4 instanceof运算符
instanceof是二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
public class Test{
public static void main(String[] args) {
Student student = new Student();
System.out.println(student instanceof Person); //判断student对象是否为Person类的实例
System.out.println(student instanceof Student);
}
}
1.5 方法的重写override
override需要符合下面三个要点:
- “==”:方法名、形参列表相同。
- “<=”:返回值类型和声明异常类型,子类小于等于父类。
- “>=”:访问权限,子类大于等于父类。
1.6 final关键字
作用:
- 修饰变量:被他修饰的变量不可改变,一旦赋了初值,就不能被重新赋值。
final int MAX_SPEED = 120;
- 修饰方法:该方法不可被子类重写,但是可以被重载。
- 修饰类:修饰的类不能被继承。比如:Math、String等。
final class A{}
1.7 继承和组合
“组合”可以实现代码复用,也就是收复并购。
“组合”不同于继承,更加灵活。
“组合”的核心就是“将父类对象作为子类的属性”,然后,“子类通过调用这个属性来获得父类的属性和方法”。
public class Animal {
public static void main(String[] args) {
Jinmao j = new Jinmao();
j.dog.shout();
j.dog.height = 10;
}
}
class Dog{
int height;
public void shout(){
System.out.println("汪汪汪");
}
}
class Jinmao{
Dog dog = new Dog();
}
继承除了代码复用,还能方便我们对事务建模。
所以对于“is-a”关系建议使用继承,“has-a”关系建议使用组合。
比如:上面的例子,Jinmao is a Dog这个逻辑没问题,但是:Jinmao has a Dog就有问题了。这时候,显然继承关系比较合适。
笔记本和芯片的关系显然是“has-a”关系,所以使用组合更好。
2.封装(encapsulation)
程序设计要追求“高内聚,低耦合”
2.1 编程中封装的优点
- 提高代码的安全性
- 提高代码的复用性
- “高内聚”:封装细节,便于修改内部代码,提高可维护性
- “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作
2.2 封装的实现——使用访问控制符
修饰符 | 同一个类 | 同一个包中 | 子类 | 所有类 |
---|---|---|---|---|
private | √ | |||
default | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
【注】关于protected的两个细节:
- 若父类和子类在同一个包中,子类可以访问父类的protected成员,也可访问父类对象的protected成员。
- 若父类和子类不在同一个包中,子类可以访问父类的protected成员,不能访问父类对象的protected成员。
public class Teacher extends Person{
public void test(){
System.out.println(super.testProtected); //可以访问父类的protected成员
}
public static void main(String[] args) {
Person p1 = new Person(); //创建父类对象
System.out.println(p1.testProtected); //子类不能访问父类对象的protected成员
}
}
//子类Teacher和父类Person不在同一个包中
2.3 封装的使用细节
开发中封装的简单规则:
- 属性一般使用private访问权限
- 属性私有后,提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(注意:boolean变量的get方法是is开头)
- 方法:一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。
JavaBean的封装演示:
public class Person {
private String name;
private int age;
private boolean flag;
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||age > 150){
System.out.println("年龄格式不合法");
}else{
this.age = age;
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
3 多态(polymorphism)
3.1 多态概念和实现
概念:多态指的是同一个方法调用,由于对象不同可能会有不同的行为。
要点:
- 多态是方法的多态,不是属性的多态(多态与属性无关)。
- 多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。
- 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
多态实例:
public class Animal {
public void shout(){
System.out.println("叫了一声");
}
}
class Dog extends Animal{
@Override
public void shout() {
System.out.println("汪汪汪");
}
}
class Cat extends Animal{
@Override
public void shout() {
System.out.println("喵喵喵");
}
}
class Mouse extends Animal{
@Override
public void shout() {
System.out.println("吱");
}
}
public class Test {
static void animalShout(Animal a){ //等于Animal a = dog;
a.shout(); //父类引用指向子类对象
}
public static void main(String[] args) {
Dog dog = new Dog();
animalShout(dog);
animalShout(new Cat());
}
}
若没有多态,将会写很多个重载方法:
public class Test {
static void animalShout(Dog a){ //多次重载
a.shout(); //如果之后要加其他的动物类,且有shout()方法,又需要重新添加重载方法
} //会使得程序耦合性很高,改起来也很不方便
static void animalShout(Cat a){
a.shout();
}
static void animalShout(Mouse a){
a.shout();
}
public static void main(String[] args) {
Dog dog = new Dog();
animalShout(dog);
animalShout(new Cat());
}
}
3.2 对象转型(casting)
定义类:
public class Animal {
public void shout(){
System.out.println("叫了一声");
}
}
class Dog extends Animal{
@Override
public void shout() {
System.out.println("汪汪汪");
}
public void seeDoor(){ //子类特有方法
System.out.println("看门");
}
}
向上类型转换(自动):
Animal animal = new Dog();
//Java会自动认为animal是Animal类型的,调用不了Dog里特有的方法
//若需要调用子类特有方法时,需要向下转型
向下类型转换(强制):
Animal animal = new Dog();
// animal.seeDoor(); 因为seeDoor()是子类Dog特有方法,所以不能调用
if (animal instanceof Dog){ //判断animal是否为Dog类型
Dog dog =(Dog) animal; //向下类型转换
dog.seeDoor(); //此时则可以调用子类特有方法了
}else if (animal instanceof Cat){
Cat cat = (Cat) animal; //由于animal是new的Dog对象,所以此时编译通过,运行不通过
//会报错,java.lang.ClassCastException:类型转换异常
}