多态是继封装、继承之后,面对对象的第三大特征。
多态的现实意义:
多态的定义:父类类型 变量名 = new 子类类型();
多态的理解:
多态中成员的特点:
Person p = new Student();
System.out.println(p.num); // num 是 Person 中的值
Person p = new Student();
System.out.println(p.show()) // 调用的是 Student 中重写的方法
instanceof
关键字:用来判断某个对象是否属于某种数据类型,返回类型为布尔类型:
public class Test {
public static void main(String[] args) {
Person p = new Student();
if (p instanceof Student) {
System.out.println("p 是 Student 类型");
} else {
System.out.println("p 不是 Student 类型");
}
}
}
// p 是 Student 类型
多态的转型:分为向上转型和向下转型
父类类型 变量 = new 子类类型()
。当不需要面对子类类型时,通过使用父类的功能就能完成相应的操作;子类类型 变量 = (子类类型)父类类型变量
。当需要使用子类特有的功能时,可以使用向下转型;public class Test {
public static void main(String[] args) {
Person person = new Student();
person.eat(); // student eat
Student student = (Student) person;
student.study(); // student study
}
}
class Person {
public void eat() {
System.out.println("people eat");
}
}
class Student extends Person {
@Override
public void eat() {
System.out.println("student eat");
}
public void study() {
System.out.println("student study");
}
}
class Teacher extends Person {
@Override
public void eat() {
System.out.println("teacher eat");
}
public void teach() {
System.out.println("teacher teach");
}
}
请问,题目的运行结果是什么?
public class Test {
public static void main(String[] args) {
Shape shape = new Shape();
shape.show(); // shape
Circle circle = new Circle();
circle.show(); // circle
CircularCone circularCone = new CircularCone();
circularCone.show(); // circular cone
}
}
class Shape {
public void show() {
showShape();
}
public void showShape() {
System.out.println("shape");
}
}
class Circle extends Shape {
@Override
public void showShape() {
System.out.println("circle");
}
}
class CircularCone extends Circle {
@Override
public void show() {
super.show();
}
@Override
public void showShape() {
System.out.println("circular cone");
}
}
多态分为两种:
多态的作用:消除类型之间的耦合关系。
多态存在的三个必要条件:继承、重写、父类引用指向子类对象。
多态的好处:
Demo 1:
在上面的例子中,当 Father 的 getName()
方法被注释掉以后,调用 father.getName()
方法会出错。因此,当父类引用指向子类方法时,必须调用那些父类中存在的方法,如果子类中对该方法进行了重写,那么在运行时就会动态调用子类中的方法,这就是多态。修改如下:
public class Test {
public static void main(String[] args) {
Test test = new Test();
// 注意:采用此种方式创建实例,否则静态方法中只能创建静态内部类的实例
Test.Father father = test.new Son();
System.out.println(father.getName()); // son
}
public class Father {
private String name = "father";
public String getName() {
return this.name;
}
}
public class Son extends Father {
private String name = "son";
@Override
public String getName() {
return this.name;
}
}
}
输出 son
。继续看下面的例子:
public class Test {
public static void main(String[] args) {
Test test = new Test();
// 注意:采用此种方式创建实例,否则静态方法中只能创建静态内部类的实例
Test.Shape shape1 = test.new Shape();
Test.Shape shape2 = test.new Circle();
Test.Circle circle = test.new Circle();
Test.CircleCone circleCone = test.new CircleCone();
shape1.show(circle); // Shape and Shape
shape1.show(circleCone); // Shape and CircleCone
shape2.show(circle); // Circle and Shape
shape2.show(circleCone); // Shape and CircleCone
}
public class Shape {
public void show(Shape shape) {
System.out.println("Shape and Shape");
}
public void show(CircleCone circleCone) {
System.out.println("Shape and CircleCone");
}
}
public class Circle extends Shape {
public void show(Circle circle) {
System.out.println("Circle and Circle");
}
public void show(Shape shape) {
System.out.println("Circle and Shape");
}
}
public class CircleCone extends Circle {
public void show(CircleCone circleCone) {
System.out.println("CircleCone and CircleCone");
}
public void show(Circle circle) {
System.out.println("CircleCone and Circle");
}
}
}
shape2.show(circle)
打印出来的是 Circle and Shape
,这里为什么不是 Circle and Circle
呢?这是因为,当超类变量引用子类对象时,被引用对象的类型而不是变量的类型决定了调用谁的成员方法。但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
首先,“当超类变量引用子类对象时,被引用对象的类型而不是变量的类型决定了调用谁的成员方法”,这句话的意思也就是说,当运行 shape2.show(circle)
时,是 Circle
类来决定调用谁的方法。但是,在其父类 Shape
中并没有定义过 show(Circle circle)
方法,也就无所谓 “子类覆盖”。因此,这里就涉及到方法调用的优先级。
优先级由高到低的依次为:this.show(O)
-> super.show(O)
-> this.show((super)O)
-> super.show((super)O)
。
shape2.show(circle)
,this
指的是 shape2
,但是在 Shape
中没有找到 show(Circle circle)
方法,于是到 Shape
的父类中去找,由于 Shape
没有父类,接着到第三优先级 this.show((super)O)
,this
仍然是 shape2
,O
为 Circle
,也就是 (super)Circle
,也就是 Circle
的父类 Shape
,在 Shape
中查找 show(Shape shape)
方法,Shape
中有这个方法,但是,shape2
指向的是一个 Circle
对象,在 Circle
中重写了 show(Shape shape)
方法,因此,最终调用的是 Circle.show(Shape shape)
方法,打印出 Circle and Shape
。
接着看下面的例子:
public class Test {
public static void main(String[] args) {
Shape shape = new Circle();
shape.show(); // circle
Circle circle = new CircleCone();
circle.show(); // circle cone
}
}
class Shape {
public void show() {
show2();
}
public void show2() {
System.out.println("shape");
}
}
class Circle extends Shape {
public void show2() {
System.out.println("circle");
}
}
class CircleCone extends Circle {
public void show2() {
System.out.println("circle cone");
}
}
由于 shape = new Circle()
,在运行到 shape.show()
时,会调用 Circle.show()
方法,在 Circle
类中并没有定义这个方法,因此,会调用 Circle
的父类 Shape.show()
方法。在 Shape.show()
方法中会调用 show2()
方法,这个方法已经被子类实现了,因此调用子类的 show2()
方法。