多态
多态,顾名思义,多种形态。现在我们有一个行为当不同的对象去完成这个行为时会产生不同的状态。例如动物们都会叫,小狗叫会是汪汪叫。小猫叫则是喵喵叫。这就是多态。
多态的实现需要满足三个条件:
1.向上转型
2.子类和父类有同名的覆盖/重写方法
3.通过父类对象,调用父类和子类重写的方法
我们先来介绍向上转型。在继承关系下,可以发生向上转型,把子类的对象给到父类,即父类引用引用了子类对象。如:
Animal animal1=new Dog();
这时就发生了向上转型。
class Animal{ public void eat(){ System.out.println("正在吃饭。"); } } class Dog extends Animal{ @Override public void eat() { System.out.println("吃狗粮"); } } public class Test4 { public static void main(String[] args) { Animal animal1=new Dog(); animal1.eat(); } }
此时我们执行这样一个代码,将会打印吃狗粮,而不是吃饭。想要实现这样的向上转型,需要在子类中重写父类的方法。什么是重写方法呢?我们重写的方法,语言的方法方法名称必须相同,参数列表必须相同,返回值必须相同。中间方法的内容我们可以重新写。向上转型我们通过父类的引用调用了这个父类和子类重写的方法及调用了子类的方法。这个过程是运行时绑定,也可以称之为多态绑定。在编译时确实认为调用的是animal的eat方法。但是运行时发现此类将这个方法重新写了,就执行了子类重写的方法。我们可以称之为“编译看左,运行看右。”
我们要注意一些重写的注意事项。被private修饰的方法不能重写。被static修饰的方法不能重写。被final修饰的方法不能重写。访问修饰的限定符private<默认<protected<public。我们子类的访问修饰限定符一定要大于等于父类的。方法的返回值之前可以不同,但必须是父子类关系。构造方法不能重写。在JAVA中用@override可以标注出重写的方法。
那么现在,eat有了多种形态,也就是我们要介绍的多态。我们可以调用一个重写的方法,引用对象不一样,表现的行为就不一样。
那么我们现在认识了向上转型,那么存不存在向下转型呢?答案是存在的。但是并不建议使用。因为向下转型会不安全。我们可以看这样一个代码。
class Animal{ public void eat(){ System.out.println("正在吃饭。"); } } class Dog extends Animal{ public void run(){ System.out.println("狗在跑"); } } public class Test4 { public static void main(String[] args) { Animal animal1=new Dog(); Dog dog=(Dog)animal1; ((Dog) animal1).run(); } }
animal明明不会跑,却要跑,会很不安全。
抽象类
所有对象都是通过类来描述的,但并不是所有类都是用来描述对象的。这就是我们今天要介绍的抽象类。我们可以使用abstract来修饰一个类。这时这个类就变成了抽象类。同样我们可以使用abstract修饰一个方法,这个方法就变成了抽象方法。被abstract消失的方法称为抽象方法,这个方法可以没有具体的实现。抽象类当中可以有和普通类一样的成员变量和成员方法。
抽象类不能被实例化,抽象类创造出来的目的就是为了继承。当一个普通类继承抽象类之后,这个普通类当中一定要重写这个抽象类当中所有的抽象方法。Final和abstract的不共存。抽象方法不能被private修饰。
那么我们前面介绍的animal这个类就可以是抽象类。
abstract class Animal{ abstract void eat(); } class Dog extends Animal{ @Override void eat() { System.out.println("吃狗粮"); } public void run(){ System.out.println("狗在跑"); } }
这个animal就是一个抽象类。
接口
接口是多个类的公共规范,一种引用数据类型。我们可以使用interface来定义接口。接口中的成员默认public static final来修饰,成员方法默认public abstract修饰,一般不写,接口中不可以有普通成员方法。接口不能通过new实例化。
nterface Running{ public void run(); } class DOG implements Running{ @Override public void run() { System.out.println("小狗在跑"); } }
java支持实现多个接口,这样可以弥补我们实现不了的多继承。接口之间也可以进行继承。