多态(Polymorphism)
1,概念
多种形态
水–放在不同的容器中,产生不同的形态
官方说:
- 接口的多种不同的实现方式即为多态。
Animal a = new Dog();
Animal b = new Cat();
Animal c = new Pig();
- 多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术。
- 我们在程序中定义的引用变量所指向的具体类型和通过该引用变量的方法调用在编程的时候并不确定,当处于运行期间才确定。就是这个引用变量究竟指向哪一个实例对象,在编译期间是不确定的,只有运行期才能确定,这样不用修改源码就可以把变量绑定到不同的类实例上,让程序拥有了多个运行状态,这就是多态。
说人话:
多态又分为 编译时多态和运行时多态。
编译时多态:比如重载
运行时多态:比如重写
重载式多态,也叫编译时多态。也就是说这种多态再编译时已经确定好了。重载大家都知道,方法名相同而参数列表不
重写式多态,也叫运行时多态。这种多态通过动态绑定(dynamic binding)技术来实现,是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。也就是说,只有程序运行起来,你才知道调用的是哪个子类的方法。 这种多态通过函数的重写以及向上转型来实现。
2,多态的使用
形成多态的必要条件
1,要有关系–继承
2,要有方法重写–重写式多态
3,要有向上转型–父类的引用指向子类的对象
public class Animal {
public void eat(){
System.out.println("animal eatting...");
}
}
public class Cat extends Animal{
public void eat(){
System.out.println("我吃鱼");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("我吃骨头");
}
public void run(){
System.out.println("我会跑");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Cat(); //向上转型 指向 指针
animal.eat();
Cat cat = (Cat)animal; //向下转型
int 4 double 8
int a = 1;
double d = a;
int c = d;
animal = new Dog();
animal.eat();
}
}
//结果:
//我吃鱼
//我吃骨头
3,向上转型
这就是向上转型,Animal animal = new Cat(); 将子类对象 Cat 转化为父类对象 Animal。这个时候 animal 这个引用调用的方法是子类方法。
转型过程中需要注意的问题
- 向上转型时,子类单独定义的方法会丢失。比如上面Dog类中定义的run方法,当animal引用指向Dog类实例时是访问不到run方法的,
animal.run()
会报错。 - 子类引用不能指向父类对象。
Cat c = (Cat)new Animal()
这样是不行的。
向上转型的好处
- 减少重复代码,使代码变得简洁。
- 提高系统扩展性。
4,向下转型
与向上转型相对应的就是向下转型了。向下转型是把父类对象转为子类对象
//还是上面的animal和cat dog
Animal a = new Cat();
Cat c = ((Cat) a);
c.eat();
//输出 我吃鱼
Dog d = ((Dog) a);
d.eat();
// 报错 : java.lang.ClassCastException:com.chengfan.animal.Cat cannot be cast to com.chengfan.animal.Dog
Animal a1 = new Animal();
Cat c1 = ((Cat) a1);
c1.eat();
// 报错 : java.lang.ClassCastException:com.chengfan.animal.Animal cannot be cast to com.chengfan.animal.Cat
为什么第一段代码不报错呢?相比你也知道了,因为 a 本身就是 Cat 对象,所以它理所当然的可以向下转型为 Cat,也理所当然的不能转为 Dog,你见过一条狗突然就变成一只猫这种操蛋现象?
而 a1 为 Animal 对象,它也不能被向下转型为任何子类对象。比如你去考古,发现了一个新生物,知道它是一种动物,但是你不能直接说,啊,它是猫,或者说它是狗。
向下转型注意事项
- 向下转型的前提是父类对象指向的是子类对象(也就是说,在向下转型之前,它得先向上转型)
- 向下转型只能转型为本类对象(猫是不能变成狗的)。
5,经典实例
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{
}
class D extends B{
}
public class Demo {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b)); A and A
System.out.println("2--" + a1.show(c)); A and A
System.out.println("3--" + a1.show(d)); A and D
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
-
打印机实例:
同样是打印机,调用打印方法,结果不同