多态:是具有表现多种形态能力的特征。更专业的说法就是:同一个实现接口,不同的实例而执行不同的操作。
对象具有两种类型:
1):编译类型: 声明对象变量的类型 Animal表示把对象看出什么类型
2):运行类型: 对象的真实类型 Dog.运行类型一→对象的真实类型.
编译运行必须和运行类型的父类或相同
当编译运行和运行类型不同的时候,多态就出现了
所谓多态 : 对象具有多种形态,对象可以存在不同的形式
Animal a = new Dog(); // a此时表示Dog类型的形态
a = new Cat(); // a 此时表示Cat 类型的形态
多态的前提: 可以是继承关系(类和类) / 也可以是实现关系(接口和实现类). 在开发中多态一般都是第二种.
多态的特点: 把子类对象赋给父类变量,在运行时期会表现出具体的子类特征.(调用子类方法)
多态的好处:
把不同的子类对象都当做父类类型来看待,可以屏蔽不同子类对象之间的实现差异,从而写出通用的代码达到通用编程,以适应需求的不断变化.
多态方法调用问题
多态时方法调用问题:
前提: 必须先存在于多态情况.
测试: 父类 Animal 子类Dog 方法eat;
测试代码:
Animal up = new Dog(); //多态
Up.eat(); //输出什么结果?
情况一: eat方法存在于Animal(父类) 中,不存在于Dog(子类)中;
此时执行结果:编译通过,执行Animal的eat方法.
应该先从Dog 类中去找eat方法,找不到再去父类Animal中查找.
情况二:eat方法存在于Dog(子类)中,不存在与 Animal(父类) 中
此时执行结果:编译错误,
编译时期:会去编译类型(Animal)中找是否有eat方法;
找 到:编译通过,
找不到:编译报错.
情况三:eat方法 即存在于Animal(父类) 中 也存在于Dog(子类)中.
执行结果:
此时执行结果:编译通过,执行Dog的eat方法.
在运行时期,调用运行类Dog(子类) 中的方法.
情况三:eat方法 即存在于Animal(父类) 中 也存在于Dog(子类)中.但是eat是静态方法
此时这种情况,称之为隐藏,而不叫覆盖
此时执行结果:编译通过,执行Animal的eat方法.
静态方法的调用只需要类即可,
如果使用对象来调用静态方法,其实使用的是对象的编译类型来调用静态方法
和对象没有关系.
引用类型转换
引用类型的转换:
引用类型的大和小,指的是父类和子类的关系
自动类型转换:把子类对象赋给父类变量(多态)
Animal a = new Dog();
Object是所有类的根类;
Object obj = new Dog(); //此时是成立的,但是obj能调用Dog类里面的方法吗? 不能,因为在Object类中没有Dog类方法,所有编译报错
强制类型转换:把一个父类类型的对象赋给子类类型的变量.(但是该父类类型变量的真实类型是子类类型)
Animal a = new Dog();
Dog b = (Dog) a ;
Instanceof 运算符 : 判断该对象是否是一个类的实例.
语法格式: booelan b = 对象A instanceof 类B //判断A对象是否是B类的实例,如果是,返回true,否则返回false.
组合关系
继承关系:子类可以继承父类中部分的成员,那么此时子类是可以修改到父类的信息的
继承关系破坏封装,为了复用代码可能会让子类具有不该有的功能.
---------------------------------------------
为什么引入进程:为了代码复用
解决代码复用问题:不一定非要使用继承,也可以使用 ”包含” 关系(has a )
一. 继承关系(破坏封装)
二.组合关系(类与对象的关系)
如果A类为了得到B类的功能行为:
如果A类是B类的一种特殊情况,我们就应该采用继承关系来实现.
否则使用组合体.
字段不存在多态特征
通过对象调用字段,在编译时期就已经决定了调用那一块内存空间的数-----因为:字段不存在覆盖的概念,在多态时,不能有多态特征(在运行时期体现子类特征).
当子类和父类存在相同的字段的时候,无论修饰是什么(即使是private),都会在各自的类空间中储存数据.