HOME
HOME

java多态

一直对面向对象中的多态模模糊糊,学了忘,忘了学。这次深入学习java,在此记录下,便于以后复习。

多态是面向对象编程语言中,与封装、继承并列为面向对象的三大特征。多态简单来说就是对象在编程时不确定具体的类型,而在运行时候才确定具体类型。

最简单的举例就是animal、cat、dog的故事。

定义animal父类如下:

1
2
3
4
5
public class Animal {
public void shout(){
System.out.println("animal shout");
}
}

定于Dog类如下:

1
2
3
4
5
6
public class Dog extends Animal{
@Override
public void shout() {
System.out.println("dog wang wang wang");
}
}

定义Cat类如下:

1
2
3
4
5
public class Cat extends Animal{
public void shout(String sound){
System.out.println("cat shout" + sound);
}
}

最后调用几个类的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
public static void main(String[] args) {
Animal animal = new Dog();
animal.shout();
Animal animal1 = new Cat();
animal1.shout();
}
}

//运行结果
dog wang wang wang
animal shout

我们定义了两个Animal类型的animalanimal1。分别指向Dog和Cat的类实例。由于Cat和Dog均是继承于Animal类的,所以该处会进行向上转型,会丢掉子类自己定义的方法,只能调用定义类型的父类中的方法。

所以定义的animal1实例,虽然指向Cat类的实例,但是由于向上转型,所以无法调用自己定义的重载带有参数的public void shout(String sound)方法。

而animal实例指向的是Dog类型,Dog类型中重写了父类的shout无参的方法,所以根据java的多态特性,可以在运行时确定对象的类型,所以animal实例能够指向自身的shout类,打印出dog wang wang wang

所以对于多态可以有如下的总结:

向上转型的子类的实例对象,无法调用由于向上转型而丢失的子类方法。但是根据多态的特性,能够在运行时,调用子类中对于父类进行重写的方法。也就是能够在运行时确定调用的具体方法。

所以实现多态必须包含三个条件:继承、重写、向上转型。

经典案例

A类:

1
2
3
4
5
6
7
8
9
public class A {
public String show(D obj){
return "A and D";
}

public String show(A obj){
return "A and A";
}
}

B类:

1
2
3
4
5
6
7
8
9
10
public class B extends A{
public String show(B obj) {
return "B and B";
}

@Override
public String show(A obj){
return "B and A";
}
}

C类:

1
2
public class C extends B{
}

D类:

1
2
public class D extends  B{
}

Test类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Test {
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)); // ==> B and A
System.out.println("5 -- " + a2.show(c)); // ==> B and A
System.out.println("6 -- " + a2.show(d)); // ==> A and D
System.out.println("7 -- " + b.show(b)); // ==> B and B
System.out.println("8 -- " + b.show(c)); // ==> B and B
System.out.println("9 -- " + b.show(d)); // ==> A and D
}
}

在看java多态的代码的时候,记住一个点,基类类型的对象,能够调用的方法包括基类本身的方法以及子类中重写的基类的方法。

对于以上代码的解释如下:

  1. a1.show(b):b的类型是b,所以对象b在a1调用的show方法上会发生向上转型,b的基类是A,所以只能调用A类中的show(A obj)方法。
  2. a1.show(c):c的类型是c,所以这里也一样会发生向上转型,调用A类中的show(A obj)方法。
  3. a1.show(d):因为A类中直接定义了show(D obj)方法,所以直接调用。
  4. a2.show(b):a2的调用会发生多态。a2的show方法包含基类的show方法和B类型中重写的show(A obj)方法。所以a2的show一共有三个方法可以进行调用。a2.show(b)在这三种方法中没有对应的方法,所以b对象会发生向上转型,同时发生多态动态调用重写的方法。最后调用的是B类中的show(A obj)
  5. a2.show(c):该处c同样会发生向上转型以及多态,最后调用的仍然是B类中的show(A obj)
  6. a2.show(d):因为在基类A中直接定义了show(D obj)的方法,因此直接调用该方法。
  7. b.show(b):b对象调用的方法包含基类A和本身B类的所有方法。所以该处直接调用show(B obj)方法
  8. b.show(c):A和B类中均无对应的方法,所以c会发生向上转型,匹配到show(B obj)方法
  9. b.show(d):A类中直接有对应的方法,直接调用show(D obj)

以上便是本次总结的关于java多态的相关知识,更多的知识可以参考《java编程思想》进一步学习。