1、存在继承关系
2、子类要重写父类的方法
3、父类数据类型的引用指向子类对象。
主函数中A a=new B();语句在堆内存中开辟了子类(B)的对象,并把栈内存中的父类(A)的引用指向了这个B对象。
向上转型个人认为是统一格式,也可以认为是花木兰替父从军 可能还有别的花小兰花二兰 她们都替自己的父亲从军但是使用的名字 年龄都是父亲的
对象多态性的本质指的就是子类和父类对象间的互相转换。
现在已经学习完了关于继承的所有概念,但是并不意味着只要使用继承就可以实现代码的全部重用,
而在继承之后又有了个重要的核心概念:多态性;
在java里面对于多态的核心表现主要有以下两点:
·方法的多态性:
|-方法的重载:同一个方法名称可以根据参数的类型及个数不同调用不同的方法体;
|-方法的覆写:同一个父类的方法可能根据实例化的子类不同也有不同的是实现;
·对象的多态性(前提:方法覆写):
|-【自动,90%】对象的向上转型:父类 父类对象=(父类 此括号可写可不写)子类实例;A a=new B();
|-【强制,1%】对象的向下转型:子类 子类对象=(子类)父类实例;B b=(B) A;
|- 9%是不进行转型,例如:String;因为String类是给主函数直接操作的如果能转型就乱套了
范例:回顾一个简单程序
class A{
public void print() {
System.out.println("【A】public void print()");
}
}
class B extends A{
public void print() {
System.out.println("【B】public void print()");
}
}
public class TestDemo {
public static void main(String[] args) {
B b=new B();//实例化子类对象
b.print();//调用被覆写的方法
}}
结果【B】public void print()
于是可以将以上的代码进一步变化,变为向上转型:
范例:实现向上转型
class A{
public void print() {
System.out.println("【A】public void print()");
}
}
class B extends A{
public void print() {
System.out.println("【B】public void print()");
}
}
public class TestDemo {
public static void main(String[] args) {
A a=new B();//向上转型
a.print();
}}
不管是否发生了向上转型,那么其核心的本质还是在于:
你使用的是哪个子类(new在哪里),而后 你调用的方法是否被子类所覆写了。
向下转型指的是将父类对象变成子类对象,但是在这之前需要首先明确一个核心概念,
为什么需要向下转型?
当你需要使用到子类扩充操作的时候就要采用向下转型
范例:向下转型
class A{
public void print() {
System.out.println("【A】public void print(){}");
}
}
class B extends A{
public void print() {
System.out.println("【B】public void print(){}");
}
public void funB() {//这个方法只有子类偶有
System.out.println("【B】public void funB(){}");
}
}
public class TestDemo {
public static void main(String[] args) {
A a=new B();//向上转型
//这个时候父类能够调用的方法只能的自己本来定义好的方法
//并没有B类中的funB()方法,那么只能够进行向下转型处理
B b=(B) a;//向下转型
b.funB();
}}
[此概念一般开发中用不到] 但是并不是所有的父类对象都可以向下转型:如果要想进行向下转型操作之前一定要首先发生向上转型,否则在转型时会出现:ClassCastException(类异常转换)
范例:错误的转型
class A{
public void print() {
System.out.println("【A】public void print(){}");
}
}
class B extends A{
public void print() {
System.out.println("【B】public void print(){}");
}
public void funB() {//这个方法只有子类偶有
System.out.println("【B】public void funB(){}");
}
}
public class TestDemo {
public static void main(String[] args) {
A a=new A();//实例化父类对象
B b=(B) a;//强制转换
}}
我们可以把父类A当成一个不知道有自己孩子的父亲 而子类B身上有父亲的特征所以他清楚谁是他父亲
正确的做法应该是:先有上然后再有下
public class TestDemo {
public static void main(String[] args) {
A a1=new B();
B b=(B) a1;//强制转换
b.funB();
}}
但是现在就有一个问题出现了,如果向下转型可能存在有隐患,那么如何转型才靠谱呢?
最好的做法是先进行判断,而后再进行转型,那么就可以依靠instanceof关键字来实现了,此关键字的使用语法如下:
· 子类对象 instanceof 类,返回的是boolean型数据;
范例:观察instanceof关键字的使用
引用A B类
public class TestDemo {
public static void main(String[] args) {
A a=new B();//实例化父类对象
System.out.println(a instanceof A);
System.out.println(a instanceof B);
}}
通过子类对象是实例化的父类,所以子类对象实例化时一定会同时实例化父类对象
所以代码的执行结果是
true true
但是当我把 new B();改成new A();时
结果为
true false
再观察入如下代码
public class TestDemo {
public static void main(String[] args) {
A a=new B();//实例化父类对象
System.out.println(a instanceof A);
System.out.println(a instanceof B);
//以后对于子类的特殊操作尽量慎用
if(a instanceof B) {//避免ClassCastException问题
B b=(B)a;
b.funB();
}
}}
虽然清楚了一系列的操作关系,可是还必须思考,这种转换有什么意义?
范例:要求定义一个方法,而这个方法而可以接受Person类的所有子类实例,并调用Person类方法:
class Person{
public void takeoff() {
System.out.println("要迟到了。。。");
}
}
class Student extends Person{
public void takeoff() {
System.out.println("又要迟到了....");
}
}
class Teacher extends Person{
public void takeoff() {
System.out.println("哎,又要迟到了");
}
}
public class TestDemo {
public static void main(String[] args) {
in(new Student());
in(new Teacher());
//不管传入进来的是学生还是老师 都是会迟到,这是对象多态性的好处
}
public static void in(Person per) {//对象多态性
per.takeoff();
}
//如果不使用对象多态性就要重载多个方法很复杂
/*例如
* public static void in(Student stu){
* stu.takeoff();}
* public static void in(Teacher tea)}{
* tea.takeoff();}
* */
}
通过以上的分析就可以清楚,对象的向上转型又一个最为核心的用处;操作参数统一
1.对象多态性实现的核心在于方法的覆写;
2.通过对象的向上转型可以实现接收参数的统一,而向下转型可以实现子类扩充方法的调用(一般不操作向下转型 了解即可 ,不过也挺重要的 );
3.两个没有关系的类对象,是不能够转型的,一定会发现生ClassCastException,所以向下转型是存在安全隐患的。
最后再看一个向上转型加深印象
class Person{
public void takeoff() {
System.out.println(
"要迟到了。。。");
}
}
class Student extends Person{
public void takeoff() {
System.out.println("又要迟到了....");
}
}
class Teacher extends Person{
public void takeoff() {
System.out.println("哎,又要迟到了");
}
}
public class TestDemo {
public static void main(String[] args) {
Student stu=new Student();//先实例化子类对象
Person per= (Person) stu;//向上转型 (Person)可写可不写
per.takeoff();//父类调用子类方法
Student stu1=(Student) per;//向下转型 基本用不到
per.takeoff();
}
}//又要迟到了....
又要迟到了....