前面介绍了面向对象编程中的封装继承组合的内容,这里继续介绍多态的内容。
三、多态
多态涉及到三个方面,向上转型、动态绑定、方法重写。
1.向上转型
首先先明确,向上转型的发生时机有三种:直接赋值、方法传参、方法返回。
1.1直接赋值
假设有两个类,Animal和Dog类,其中Dog类继承自Animal类。
Dog dog = new Dog();
也可以写作:
Dog dog = new Dog();
Animal dog1 = dog;
也可以直接写作:
Animal dog1 = new Dog();
此时 dog1 是一个父类 (Animal) 的引用, 指向一个子类 (Dog) 的实例. 这种写法称为 向上转型。
1.2方法传参
class Animal{
public void eat(String name){
System.out.println(name + "正在进食!");
}
}
class Dog extends Animal{
public void bite(String name){
System.out.println(name + "正在咬人!");
}
}
public class Demo1 {
public static void main(String[] args) {
Dog dog = new Dog();
use(dog);
}
private static void use(Animal animal) {
animal.eat("大黄");
}
}
这里,dog作为参数是Animal的引用,指向Dog实例。
1.3方法返回
class Animal2{
public Animal2(){
System.out.println("Animal2的构造方法被使用了!");
}
}
class Dog2 extends Animal2{
public Dog2(){
System.out.println("Dog2的构造方法被使用了!");
}
}
public class Demo2 {
public static void main(String[] args) {
Animal2 animal2 = use();
}
private static Animal2 use() {
Dog2 dog2 = new Dog2();
return dog2;
}
}
这里dog2是Animal2的引用,是Dog2的实例。
2.动态绑定
当子类和父类的方法重名时,调用会出现什么情况呢?
class School {
public String name;
public School(String name){
this.name = name;
}
public void printOut(String name){
System.out.println("这是学校");
System.out.println(this.name + "的别名是" + name);
}
}
class Teacher extends School{
public Teacher(String name){
super(name);
}
public void printOut(String name){
System.out.println("这是老师");
System.out.println(this.name + "的小名是" + name);
}
}
public class Demo3 {
public static void main(String[] args) {
School school1 = new School("红星小学");
School school2 = new Teacher("张老师");
school1.printOut("红小");
school2.printOut("花花");
}
}
打印结果:
这是学校
红星小学的别名是红小
这是老师
张老师的小名是花花
可以看到,school1和school2都是School的引用,但指向的实例不同,所以具体调用到的方法也不同,这就是动态绑定。
3.方法重写
针对刚才的 printOut 方法来说:
子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override).
1.要注意区别重写与重载的区别,重载的规则是方法名相同,参数的个数或类型不同。
2. 普通方法可以重写, static 修饰的静态方法不能重写.
3. 重写中子类的方法的访问权限不能低于父类的方法访问权限.
4. 重写的方法返回值类型不一定和父类的方法相同
另外, 针对重写的方法, 可以使用 @Override 注解来显式指定。
写一个用到多态的小程序
class Shape{
protected double s;
public Shape(){
}
public void calculate(){
}
}
class Circle extends Shape{
private int r;
public Circle(int r){
this.r = r;
}
public void calculate(){
System.out.println("圆的面积是:" + 3.14 * r * r);
}
}
class Rect extends Shape{
private int a;
private int b;
public Rect(int a , int b){
this.a = a;
this.b = b;
}
public void calculate(){
System.out.println("矩形的面积是:" + a * b);
}
}
public class Demo4 {
public static void main(String[] args) {
Shape shape1 = new Circle(3);
Shape shape2 = new Rect(2 , 5);
shape1.calculate();
shape2.calculate();
}
}
打印结果:
圆的面积是:28.259999999999998
矩形的面积是:10