多态
多态是指一个引用可以指向多个对象,能够表现出多种形态。多态是方法的多态,属性没有多态。
多态存在的条件:
-
有继承关系
-
子类重写父类方法
-
父类引用指向子类对象
使用多态的好处:
-
类的调用者对类的使用成本进一步降低
-
能够避免使用大量的if-else
-
可扩展能力更强
向上转型
向上转型可以理解为父类引用了子类的对象,但是注意:父类虽然引用了子类对象,但引用只能访问父类中所有的成员,无法访问子类中特有的成员。
向上转型发生的时机:
-
直接赋值
-
方法传参
-
方法返回
如:
class Animal {
public String name;
public int a = 20;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(this.name + "eat");
}
}
//类Dog继承了类Animal
class Dog extends Animal{
public int a = 10;
public int b = 30;
public Dog(String name) {
super(name);//调用父类的构造方法
}
public void bark() {
super.eat();
System.out.println(this.name + "wangwang");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Dog("花花");//向上转型(直接赋值)
System.out.println(animal.name);
System.out.println(animal.a);
//animal的类型是Animal,只能访问Animal类自己的成员,不能访问Dog类中特有的b
//System.out.println(animal.b);
}
}
向下转型
向上转型是父类引用子类对象,那么向下转型就是子类引用父类对象,但是向下转型之前先要进行向上转型,相比于向上转型,向下转型不够安全。
如:
class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(this.name + "eat");
}
}
//类Bird继承类Animal
class Bird extends Animal{
public Bird(String name) {
super(name);//调用父类的构造方法
}
public void fly() {
System.out.println(this.name + "fly");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Bird("菲菲");
Bird bird = (Bird)animal;//向下转型
bird.fly();
}
}
可以用instanceof来判定一个引用是否是某个类的实例,如果是,则返回true,这时进行向下转型就比较安全了。
如:
public static void main(String[] args) {
Animal animal1 = new Bird("菲菲");
if(animal1 instanceof Bird) {//判断animal1是不是Bird的实例
Bird bird = (Bird)animal1;//向下转型
bird.fly();
}
}
动态绑定
动态绑定也叫做运行时绑定,是指父类和子类中有同名的方法时,调用的是父类的方法还是子类的方法,要看这个引用指向的是父类对象还是子类对象,这个过程是程序运行时决定的,而不是编译期。
动态绑定发生的条件:
-
发生向上转型(父类引用子类对象)
-
父类和子类有同名的重写/覆盖/覆写方法
-
通过父类的引用调用子类和父类同名的重写方法
class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(this.name + "eat");
}
}
//类Dog继承了类Animal
class Dog extends Animal{
public Dog(String name) {
super(name);//调用父类的构造方法
}
public void bark() {
super.eat();
System.out.println(this.name + "wangwang");
}
public void eat() {
System.out.println(this.name + "Dog eat");
}
}
public class Test {
public static void main(String[] args) {
Animal animal1 = new Animal("发发");
animal1.eat();//animal1指向Animal类的实例,调用的是Animal类中的eat方法
Animal animal2 = new Dog("花花");
animal2.eat();//animal2指向Dog类的实例,调用的是Dog类中的eat方法
}
}
}
方法的重写
重写(override):方法名称、参数列表的个数和类型以及返回值都相同。
重载(overload):方法名相同、参数列表类型和个数不同、返回值不做要求(可以有也可以没有)。
注意:
-
普通方法可以被重写,被static修饰的静态方法不能被重写。
-
子类如果重写父类的方法,子类的方法访问权限不能低于父类的方法访问权限。
-
父类当中被重写的方法不能是private的方法。
-
被final修饰的方法不能被重写,称为密封方法。