JAVA基础语言面向对象之——多态、抽象类
多态
-
多态的概念:
“is-a"规则可以用来判断是否应该将数据设计为继承关系,它表明子类的每个对象也是父类的对象,例如:每个猫都是动物,因此将Cat类设计为Animal类的子类是显而易见的,反之不然。
“is-a”规则的另一种表述法是置换法则,它表明程序中出现父类对象的任何地方都可以用子类对象来置换。例如:可以将一个子类的对象赋给父类的引用。Cat cat = new Cat(); Animal animal = new Cat();。在java中,将父类的引用赋给子类对象是不允许的。
在JAVA程序设计语言中,对象变量是多态的。一个Animal类型变量既可以引用一个Animal类型对象,也可以引用一个Animal类的任何一个子类的对象,例如Animal animal = new Animal(); Animal animal = new Cat(); Animal animal = new Dog();等。 -
多态的前提:
a:要有继承关系。
b:要有方法重写。 其实没有也是可以的,但是如果没有这个就没有意义。
c:要有父类引用指向子类对象。父 f = new 子(); -
案例演示:
多态的体现public class MyTest { public static void main(String[] args) { //多态,父类引用指向的是子类对象 Animal an=new Cat(); an.sleep(); an.eat(); an.show(); } } class Animal{ public void eat(){ System.out.println("吃饭"); } public void sleep() { System.out.println("睡觉"); } public void show() { System.out.println("父类中的show方法"); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫爱吃鱼"); } @Override public void sleep() { System.out.println("猫爱白天睡觉"); } }
多态中的成员访问
-
A:多态中的成员访问特点:
a:成员变量,使用的还是父类的变量
编译看左边,运行看左边。
b:构造方法
创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化。
c:成员方法
编译看左边,运行看右边。
d:静态方法
编译看左边,运行看左边。(静态和类相关,算不上重写,所以,访问还是左边的) -
B:案例演示:
多态中的成员访问特点public class MyTest { public static void main(String[] args) { Fu fu = new Zi(); System.out.println(fu.num); //以多态的形式来访问成员变量 fu.show(); //多态的形式访问成员方法,动态绑定 Fu.hehe(); //静态绑定 } } class Fu{ int num = 100; public void show(){ System.out.println("父类的show方法"); } public static void hehe(){ System.out.println("父类的静态方法"); } } class Zi extends Fu{ int num=10; @Override public void show() { System.out.println("子类重写过后的show方法"); } public static void hehe() { System.out.println("子类的静态方法"); } }
运行结果: 100 子类重写过后的show方法 父类的静态方法
- 此程序的内存图如下:
- 此程序的内存图如下:
-
C:绑定机制:
静态绑定:调用成员方法的时候,如果方法是private、static、final或构造方法,那么编译器将可以准确地知道应该调用哪个方法。 例如:Fu.hehe();调用父类的静态方法。
动态绑定:调用成员方法的时候,a)若存在方法重载,编译器将根据参数的实际类型寻找调用的方法(此过程称为重载解析)。b)若子类对父类的方法进行重写,则调用此方法的时候,执行子类重写后的方法。此类过程称为动态绑定。例如:fu.show(); 调用的时候执行子类重写后的show方法。
动态绑定的一个重要特性:无需对现存代码进行修改,就可以对程序进行扩展。假设新增一个新类S on,并且变量fu有可能引用这个类的对象,我们不需要对包含调用fu.show()的代码进行重新编译,只需在此类中重写show()方法。 -
多态的好处:
a:提高了代码的维护性(继承保证)
b:提高了代码的扩展性(由多态保证) -
多态的弊端:
父类引用不能访问子类独有的功能和属性。
解决办法:向下转型,把父类的引用强制转换为子类的引用(也称为强制类型转换)。
案例演示:多态的向下转型public class MyTest { public static void main(String[] args) { Cat cat = new Cat(); Animal an=cat; //多态就是向上转型 an.eat(); Cat c= (Cat) an; //向下转型 c.eat(); c.cacheMouse(); Dog dog = new Dog(); an=dog; Dog d= (Dog) an; //向下转型 d.lookDoor(); an.eat(); Tiger t= (Tiger) an; t.goSwimming(); } } class Animal{ public void eat(){ System.out.println("吃饭"); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼"); } public void cacheMouse(){ System.out.println("猫抓老鼠"); } } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头"); } public void lookDoor(){ System.out.println("狗看门"); } } class Tiger extends Animal{ @Override public void eat() { System.out.println("老虎不吃素"); } public void goSwimming(){ System.out.println("老虎去游泳"); } }
抽象类
-
A:抽象类概述:
回想前面我们的猫狗案例,提取出了一个动物类。并且我们在前面也创建过了动物对象,其实这是不对的。为什么呢?因为,我说动物,你知道我说的是什么动物吗?只有看到了具体的动物,你才知道,这是什么动物。
所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。
抽象类就是被abstract所修饰的类,父类将所有子类的共性功能向上抽取后,他并不知道,每个子类对这个共性功能的具体实现,所以没有必要在父类中,给出共性功能的具体实现,而是给出声明即可,所谓给出功能的声明,就是将此功能抽象出来,然后强制子类必须重写,抽象的功能。 -
B:抽象类特点:
a:抽象类和抽象方法必须用abstract关键字修饰
抽象类格式: abstract class 类名 {}
抽象方法格式: public abstract void eat();
b:抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
c:抽象类中可以有构造方法,抽象类不能进行实例化,那么要构造方法有什么作用呢?
用于子类访问父类数据时的初始化
d:抽象类不能直接实例化那么,抽象类如何实例化呢?
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
e:抽象类的子类
要么是抽象类
要么重写抽象类中的所有抽象方法 -
案例演示:
假如我们在开发一个系统时需要对员工(Employee) 类进行设计,员工包含3个属性:姓名、工号以及工资(salary)。经理(Manager) 也是员工,除了含有员工的属性外,另为还有一个奖金(bonus) 属性。然后定义工作的方法。public class MyTest { public static void main(String[] args) { Person p = new Employee(); //抽象类的实例化,采用多态形式 p.name="张岚"; p.num=1; p.salary=2000; System.out.println(p.name+"=="+p.num+"==="+p.salary); p.work(); System.out.println("--------------------"); p=new Manager(); p.name = "刘林"; p.num = 2; p.salary = 4000; ((Manager) p).bonus=2000; //向下转型 System.out.println(p.name+"==="+((Manager) p).bonus+"==="+p.num); p.work(); } } //抽象类Person类 public abstract class Person { public String name; public int num; public double salary; //抽象方法 public abstract void work(); } public class Employee extends Person{ @Override //重写父类中的抽象方法 public void work() { System.out.println("员工敲代码"); } } public class Manager extends Person{ public double bonus; @Override //重写父类中的抽象方法 public void work() { System.out.println("经理管理员工"); } }
-
C:抽象类的成员特点:
a:成员变量:既可以是变量,也可以是常量。
b:构造方法:有。用于子类访问父类数据的初始化。
c:成员方法:既可以是抽象的,也可以是非抽象的。 -
D:抽象类的成员方法特性:
a:抽象方法 ,强制要求子类做的事情。抽象方法充当占位的角色,它们的具体实现在子类中。
b:非抽象方法 ,子类继承的事情,提高代码复用性。1、一个类如果没有抽象方法,可不可以定义为抽象类 ? 如果可以,有什么意义 ? 可以, 外界不能直接创建对象 2、abstract不能和哪些关键字共存 ? 不能和private 共存 矛盾;不能和 final 共存 矛盾;不能和 static 共存 没有意义