java面向对象-多态性

1. 多态性的定义

相比于封装和继承,Java多态是三大特性中比较难的一个,封装和继承最后归结于多态, 多态指的是类和类的关系,两个类由继承关系,存在有方法的重写,故而可以在调用时有父类引用指向子类对象。可以理解为一个事物的多种形态。指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式

2. 多态性的好处

  1. 可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
  2. 可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
  3. 接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
  4. 灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
  5. 简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

2.1 实现多态的技术

实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

2.2 多态的作用

多态的作用:消除类型之间的耦合关系。

3. 多态性使用:虚拟方法调用

  • 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
  • 总结:编译,看左边;运行,看右边。
  • 对象的多态:在Java中,子类的对象可以替代父类的对象使用
  • 一个变量只能有一种确定的数据类型
  • 一个引用类型变量可能指向(引用)多种不同类型的对象

4. 多态性使用前提

  • 类的继承关系
  • 方法的重写

5. 多态性应用举例

public class AnimalTest {

    public static void main(String[] args) {
        AnimalTest test = new AnimalTest();
        test.func(new Dog());

        test.func(new Cat());
    }

    public void func(Animal animal){
        animal.eat();
        animal.shout();
    }
}


class Animal{

    public void eat(){
        System.out.println("动物:进食");
    }

    public void shout(){
        System.out.println("动物:叫");
    }
}

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    public void shout(){
        System.out.println("汪! 汪! 汪!");
    }

}

class Cat extends Animal{
    public void eat(){
        System.out.println("猫吃鱼");
    }

    public void shout(){
        System.out.println("喵! 喵! 喵!");
    }

}

6. 多态性使用注意点总结

  • 对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
  • 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法

多态使用总结

  • 多态的作用:提高了代码的通用性,常称作接口重用
  • 使用前提:①需要存在继承或者实现关系 ②有方法的重写
  • 成员方法:

编译时:要查看引用变量所声明的类中是否有所调用的方法

运行时:调用实际new的对象所属的类中的重写方法

  • 成员变量:不具备多态性,只看引用变量所声明的类

7. 向上转型与向下转型

7.1 向上转型

向上转型:多态

7.2 向下转型

7.2.1 为什么使用向下转型

有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。如何才能调用子类特的属性和方法?使用向下转型。

7.2.2 如何实现向下转型

使用强制类型转换符:()

Person p = new Man();

Man m1=(Man)p2;//向下转型

7.2.3 使用时注意点

  • 使用强转时,可能出现ClassCastException的异常。
  • 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
  • 只有对象A是B的子类实例化对象或者在下层的子类,才能向下转型

7.2.4 instanceof使用

  • a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
  • 如果 a instanceof A返回true,则 a instanceof B也返回true.其中,类B是类A的父类。
  • 要求a所属的类与类A必须是子类和父类的关系,否则编译错误。

应用举例

public class InstanceTest {
    public static void main(String[] args) {
        InstanceTest test1 = new InstanceTest();
        test1.method(new Graduate());
    }

    public void method(Person e){
        //方式一
        if (e instanceof Graduate){
            System.out.println("a graduated student");
            System.out.println("a student");
            System.out.println("a person");
        }else if (e instanceof Student){
            System.out.println("a student");
            System.out.println("a person");
        }else {
            System.out.println("a person");
        }

        //方式二
        if (e instanceof Graduate){
            System.out.println("a graduated student");
        }
        if (e instanceof Student){
            System.out.println("a student");
        }
        if (e instanceof Person){
            System.out.println("a person");
        }

        //虚拟方法调用
        String info = e.getInfo();
        System.out.println(info);
    }
}


class Person{
    protected String  name = "person";
    protected int age = 50;
    public String getInfo(){
        return "Name:"+name+"\n"+"age:"+age;
    }
}

class Student extends Person{
    protected String school = "pku";
    public String getInfo(){
        return "Name:"+name+"\n"+"age:"+age+"\nschool:"+school;
    }
}
class Graduate extends Student{
    public String major = "IT";
    public String getInfo(){
        return "Name:"+name+"\n"+"age:"+age+"\nschool:"+school+"\nmajor:"+major;
    }
}

8. 面试题

8.1 谈谈你对多态性的理解

  1. 实现代码的通用性。
  2. 举例:
  • Object类中定义的public boolean equals(Object obj){ }
  • JDBC:使用java程序操作(获取数据库连接、CRUD)数据库(MySQL、Oracle、DB2、SQL Server)
  • 抽象类、接口的使用肯定体现了多态性。(抽象类、接口不能实例化)

8.2 多态是编译时行为还是运行时行为

运行时行为

代码演示

class Base {
	int count = 10;

	public void display() {
		System.out.println(this.count);
	}
}

class Sub extends Base {
	int count = 20;

	public void display() {
		System.out.println(this.count);
	}
}

public class FieldMethodTest {
	public static void main(String[] args) {
		Sub s = new Sub();
		System.out.println(s.count);//20
		s.display();//20
		
		Base b = s;//多态性
		//==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同
		System.out.println(b == s);//true
		System.out.println(b.count);//10
		b.display();//20
	}
}
  • 若子类重写了父类方法,就意味着子类里面定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边
  • 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值