Java的多态性

Java面向对象的三大特性:封装(Encapsulation), 继承(Inheritance), 多态(Polymorphism) 。
多态:同一个对象 体现出来的多种不同形态(身份) , 将一种行为表现出不同的效果。
实现多态的效果的前提: 需要先有继承关系。
我们先来看看代码:
Animal 类,它默认继承的是Object类:

public class Animal {

    public String name = "Animal的name属性";

    public void eat(){
        System.out.println("animal的吃饭方法");
    }
    public void sleep(){
        System.out.println("animal的睡觉方法");
    }
}

继承Animal类的Person类

public class Person extends Animal{

    public String name = "person的name属性";

    public void eat(){
        System.out.println("person的吃饭方法");
    }
    public void sleep(){
        System.out.println("person的睡觉方法");
    }
    public void talk(){
        System.out.println("person的说话方法");
    }
}

继承Animal类的Pig 类

public class Pig extends Animal{

    public String name = "pig的name属性";

    public void sleep(){
        System.out.println("pig的睡觉方法");
    }
}

继承Person类的Student 类

public class Student extends Person {

    public String name = "student的name属性";

    public void talk(){
        System.out.println("学生遵守礼貌 应该好好说话");
    }
    public void study(){
        System.out.println("好好学习 天天向上");
    }
}

继承Person类的Teacher 类

public class Teacher extends Person{

    public String name = "teacher的name属性";
    public void eat(){
        System.out.println("做老师的通常不按时吃饭");
    }

    public void teach(){
        System.out.println("做老师的独有方法 一般人不会讲课 我会");
    }
}

我们先简单梳理一下类关系:
在这里插入图片描述

测试:

Object o = new Teacher();//自动向上转型,Teacher-->Object
o.hashCode();
o.toString();

以上代码将父类(Object)类型的引用 指向 子类(Teacher)的对象,虽然o实际上是一个Teacher对象,但是它现在充当的是Object的角色,它只能调用到Object类下的所有方法。但是,执行hashCode()方法时,先要看该对象的真实类(Teacher)是否重写该hashCode()方法,如果重写,调用的就是Teacher类重写的那个方法,如果没有重写,找Teacher类的上一级Person类,如果Person类重写了该方法,就执行Person类重写的那个方法,如果没有没有重写,继续找上一级Animal类,如此不断向上找寻···,直到该方法被成功找到。
要注意的是,之所以可以向上转型,前提是Teacher类是Object类的子类或者是Object类的子类的子类,必须具备直接或间接的继承关系。

Animal a = (Animal)o;//强制向下转型,Object--->Animal
a.hashCode();
a.toString();
System.out.println(a.name);//属性没有重写一说,animal的name属性
a.sleep();//从真实的类对象Teacher出发,Teacher没有重写  但person重写了,执行person的sleep
a.eat();//执行teacher的eat方法

在这里插入图片描述

Person p = (Person)o;//强制向下转型,Object--->Person
p.hashCode();
System.out.println(p.name);//person的name属性
p.sleep();//人类的睡觉
p.eat();//老师的吃饭
p.talk();//人类的说话

在这里插入图片描述

Teacher t = (Teacher)o;//强制向下转型,Object--->Teacher
System.out.println(t.name);//老师的name
t.eat();//老师的吃饭
t.sleep();//人类睡觉
t.talk();//人类说话
t.teach();//老师的独有方法

在这里插入图片描述


以上代码中,老师类和学生类都继承自Person类,它们是平级关系,没有继承关系,那么将teacher对象强制造型(铸型)成student对象会怎样呢?

Object o = new Teacher();
Student s = (Student)o;

这行代码编译好使,但是运行报错,它是运行时异常:java.lang.ClassCastException
cast意为铸造,铸型,它表示的是类铸型异常,不能将Teacher 类对象铸型为Student对象:Teacher cannot be cast to Student。
我们如何有效避免铸型时的异常呢?当我们不确定该类是否可以铸型为另一个类时,我们最好在前面加一个判断:

   if(o instanceof Student){//对象是否属于后面类型
       System.out.println("类型匹配  可以造型");
       Student s = (Student)o;//运行时异常 ClassCastException
       s.study();
   }else{
       System.out.println("对不起 类型不匹配 不帮您造型啦 否则会出问题");
   }

instanceof严格意义来讲应该算作是一个运算符,运算的结果是true或false,它用来判断一个对象是否属于某一个类。

总结

多态的5个体现:

  1. 父类类型的引用 指向子类的对象
    Person p = new Teacher();
  2. 该引用只能调用父类中定义的属性或方法
  3. 如果子类中将父类的方法重写,那么调取方法后执行的结果是子类重写之后的那个结果
    如果父类与子类有同名的属性 执行父类的属性
    如果父类与子类有同名的方法(重写) 执行子类重写之后的方法
  4. 若想要调用子类中独有的成员
    (强制类型转化) 造型 铸型 (向上/向下转型)
  5. 造型时(强制向下转型时) 可能会出现一个运行时异常
    ClassCastException (造型/铸型 异常)
    如果想要避免造型的异常 可以用instanceof关键字来进行判断
    instanceof严格意义来讲应该算作是一个运算符,运算的结果是true或false,它用来判断一个对象是否属于某一个类
    用法是:对象 instanceof 类

最后总结以下常见的运行时异常:
InputMismatchException 输入类型不匹配
NumberFormateException 数字格式化异常 Integer.parseInt(“abc”)
ArrayIndexOutOfBoundsException 数组索引越界
NegativeArraySizeException 数组长度负数 int [] arr = new int[-2];
NullPointerException 空指针异常 Person p = null; p.hashCode();
ArithmeticException 算数异常 10/0
ClassCastException 造型异常 将对象的类型还原时 与真实类型不匹配

运行时错误:
StackOverflowError 栈内存溢出错误

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章