多态
软件设计六大原则
1 单一职责原则 : 功能职责单一,只拥抱一种变化
2 里氏替换原则 : 所有在使用父类的情况下,都可以使用子类替换
3 依赖倒置 : 通过高层的抽象依赖底层,细节依赖抽象
4 接口隔离原则
5 迪米特原则
6 开闭原则 : 对扩展开放,对修改关闭
多态前提条件
有继承关系
多态的几种形式
1 局部变量/成员变量 : 声明的时候 使用父类声明,赋值的时候,使用子类对象
2 实参/形参 : 参数列表使用父类声明变量,方法调用时传入子类对象
3 返回值 : 返回值类型使用父类声明,return的时候 返回子类对象
**多态发生在赋值的时候**
Animal a ; // 声明一个变量,不是多态
a = new Animal(); 父类引用指向父类对象,不是多态
a= new Cat(); : 父类引用指向子类对象,多态
多态缺点
丢失子类特有的属性
父类引用指向子类对象
引用 : 引用类型变量
指向 : 就是通过这个引用类型的变量保存的内存地址,可以找到谁
子类对象 : 就是使用子类创建的对象
使用父类类型声明一个变量,这个变量保存子类对象的内存地址,
哪里 有变量,哪里就能发生多态
语法
父类 变量名 = new 子类()
1 如果父类没有,不管子类有没有,不管什么属性,都访问不了,报错
2 如果父类有的成员方法,子类也有的成员方法,执行子类,因为覆写
3 如果父类有的成员方法,子类没有,执行父类
4 如果父类有的非成员方法,不管子类有没有,都执行父类
public class Poly_01 {
public static void main(String[] args) {
Sup sup = null;
sup.m1();
System.out.println(sup.i);
// System.out.println(sup.a);
}
}
class Sup{
int i = 10;
public void m1() {
System.out.println("父类成员方法");
}
}
class Sub extends Sup{
int i = 20;
int a = 1;
public void m1() {
System.out.println("子类成员方法");
}
}
多态的好处
参数使用父类声明,可以接收所有子类对象
后续想要进行功能扩展的时候,不需要改动源码
public class Poly_02 {
public static void main(String[] args) {
Cat c = new Cat();
Dog d = new Dog();
eat(c);
eat(d);
Animal a = new Cat();
}
public static void eat(Animal animal) {
//判断animal是否由cat实例化而来
if(animal instanceof Cat) {
//向下转型
Cat c1 = (Cat) animal;
//TODO 可以访问特有属性了
}else if(animal instanceof Dog){
Dog d1 = (Dog)animal;
}
animal.eat();
}
}
class Animal{
public void eat() {
System.out.println("动物吃东西");
}
}
class Cat extends Animal{
public static final int age = 1;
public void eat() {
System.out.println("猫吃鱼");
}
}
class Dog extends Animal{
public static final int age = 1;
public void eat() {
System.out.println("狗吃肉");
}
}
多态又叫向上转型
自动类型转换:
1 基本类型 : 低精度到高精度
2 引用类型 : 子类到父类
instanceof 运算符 : 判断某个对象是否由某个类实例化而来,可以避免强制类型转换异常
public class Poly_03 {
public static void main(String[] args) {
Animal animal = new Cat();
//多态丢失子类特有属性
//System.out.println(animal.age);
//需要先向下转型
Cat c = (Cat) animal;
System.out.println(c.age);
//如果把Cat转换为Dog类型 会报错
Dog d = (Dog)animal;
//判断之后名可以避免类型转换异常
if (animal instanceof Cat) {
Cat c1 = (Cat) animal;
System.out.println(c1.age);
}else if ( animal instanceof Dog) {
Dog d1 = (Dog) animal;
System.out.println(d1.age);
}
}
}
隐秘的一个多态
通过子类,调用父类的方法的时候,父类的这个方法中的上下文环境 就会发生多态(属于父类空间,子类对象)
public class Poly_04 {
public static void main(String[] args) {
SubClass sub = new SubClass();
System.out.println(sub);
// System.out.println(sub.i);
sub.m1();
}
}
class SupClass{
int i = 10;
int asdasdacxz12 = 2;
public void m1() {
/**
* this:保存当前类对象的内存地址,并且是一个成员对象,那么this的数据类型是什么?
*
* 当前类:this在那个类体中,那个就是就是当前类
*
* 当this的数据类型是什么的时候,可以存储当前类对象的内存地址?
* 1 当前类类型
* 2 父类类型
*
* 如果是父类类型,会发生多态,丢失子类特有的属性,经过测试,可以使用this调用当前类中
* 特有的属性,所以this的类型一定是当前类类型
*
* SupClss this;
*
* 谁调用的这个方法,this就指向谁
*
* 这个m1方法是谁调用的?
* 如果是当前类对象调用的,this就指向当前类对象
* 但是如果是子类对象调用,this就指向子类对象
* 结合起来 就成了
* SupClass this = new SubClass(); 发生多态
*
*/
// System.out.println(this.asdjhaskhdask123123bdkas);
System.out.println(this);
System.out.println(this.i);
//调用不了
// System.out.println(this.b);
m2();
}
public void m2() {
System.out.println("父类m2执行");
}
}
class SubClass extends SupClass{
int i = 33;
int b = 2;
public void m2() {}
}