多态是什么?
多态是同一个行为具有不同表现形式或形态的能力(在父类中定义的属性和方法被子类继承之后)
多态实现的三个必要条件
- 继承
public class Test { //向上转型 public static void main(String[] args) { Dog dog = new Dog(); dog.name = "One"; dog.age = 1; dog.eat(); Brid brid= new Brid(); Brid.name = "Two"; Brid.age = 2; Brid.eat(); } } class Animal{ public String name; public int age; public void eat(){ System.out.println(name + "正在吃饭"); } } class Dog extends Animal{ public void wow(){ System.out.println(name + "汪汪叫"); } } class Bird extends Animal{ public void fly(){ System.out.println(name + "正在飞"); } }
- 重写
public class Test { //向上转型 public static void main(String[] args) { Dog dog = new Dog(); dog.name = "One"; dog.age = 1; dog.eat(); Brid brid= new Brid(); Brid.name = "Two"; Brid.age = 2; Brid.eat(); } class Animal{ public String name; public int age; public void eat(){ System.out.println(name + "正在吃饭"); } } class Dog extends Animal{ public void wow(){ System.out.println(name + "汪汪叫"); } //重写 //条件:1.方法名称相同 2.参数列表相同 3.返回值相同 @Override public void eat(){ System.out.println(name + "正在吃狗粮"); } } class Bird extends Animal{ public void fly(){ System.out.println(name + "正在飞"); } @Override public void eat(){ System.out.println(name + "正在吃虫子"); } }
@Override 代表了这个方法是重写的
- 父类引用指向子类的对象(向上转型)
public class Test { //向上转型 public static void main(String[] args) { Animal animal1 = new Dog(); animal1.name = "wo"; animal1.age = 2; animal1.eat(); Animal animal2 = new Bird(); animal2.name = "Wo"; animal2.age = 1; animal2.eat(); } /*public static void func(Animal animal) { } public static void main(String[] args) { Dog dog = new Dog(); func(dog); } */ class Animal{ public String name; public int age; public void eat(){ System.out.println(name + "正在吃饭"); } } class Dog extends Animal{ public void wow(){ System.out.println(name + "汪汪叫"); } } class Bird extends Animal{ public void fly(){ System.out.println(name + "正在飞"); } }
在idea中这是向上转型的图标
多态的优缺点
优点:
- 能够降低代码的“圈复杂的”(描述一段代码的复杂度),避免使用大量的if else
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
缺点:
- 必有继承
要避免在构造方法中调用重写的方法
//创建两个类,B是父类,D是子类,在D中重写func方法,并且在B的构造方法中调用
public class Test {
public static void main(String[] args) {
D d = new D();
}
}
class B{
public B(){
func();
}
public void func(){
System.out.println("B.func()");
}
}
class D extends B{
private int num = 100;
public void func(){
System.out.println("D.func()" + num);
}
}
但是代码编译运行后
num输出为0,这是为什么呢?
原因就是:在构造D对象的同时,会调用B的构造方法,此时会触发动态绑定,调用到D中的func
但是此时D对象自身还没有构造,num处于未初始化的状态,值为0
总结:
用尽量简单的方式使对象进入可工作状态,不要在构造器中调用方法(如果这个方法被子类重写,就会触发动态绑定,但是此时子类对象还没构造完成,可能会出现一些隐藏的问题)