个人笔记之多态转型问题
在转型问题的上有点小问题,有点绕,故抽出时间来整理一下思路 ( 纯属个人思考方式 ) 。
1.多态
多态就是留下一个口子(方法、函数),这个口子可以跑很多方法(函数)但是这些函数功能或许有差异,但对这些函数的操作是一样的,这样能快速使用各类函数而不需要反复地写调用语句。
举个例子:在继承中,子类可以拥有父类全部(可以使用的)的方法和属性,但若父类方法满足不了要求时就需要另写方法。具体实现最常见的是重写,若父类中自带的函数无法满足需求,子类中可以重写该方法。若运行时在子类中没有找到对应的方法,则会在父类中寻找对应的方法,直到找到Object类为止。
编译时多态:编译时就能看出来的多态(会直接报错标红)
运行时多态:运行时,调用各个new出来的函数时才能体现的多态,一般编译时不报错,跑起来才报错。
而转型时遇到的比较麻烦的问题就是运行时多态–编译时不报错但运行时报错
故简单分析下转型多态问题
首先创建两个类,父类A和子类B。(为了方便起见就不用变量举例子了)
父类A写了个 printA 方法, 打印printAA
class A{
void printA(){
System.out.println("printAA");
}
}
子类B继承A,写了个printB方法,打印printBB
class B extends A{
void printB(){
System.out.println("printBB");
}
}
再来个main方法,先正常创建AB,然后给AB各种转换都来一下,跑一(N)下
-
public static void main(String[] args) { //new 个 A 和 B A a = new A(); a.printA(); B b = new B(); b.printB(); // 用 a 引用 new B A a1 = new B(); a1.printA(); !// a1.printB(); //报错了 ((B) a1).printB(); //修正后 跑出来了 // 这里就是将a1强转为B System.out.println("***********************************"); // 用 b 引用 new A !// B b1 = new A(); //报错,此时没有自动转换,需要强转 System.out.println("===B b0 = (B) new A(); : ==="); /* Exception in thread "main" java.lang.ClassCastException: com.cl251ka.demo005.A cannot be cast to com.cl251ka.demo005.B at com.cl251ka.demo005.DuoTai.main(DuoTai.java:18)*/ !// B b0 = (B) new A();//报了个异常 // b0.printA(); // b0.printB(); System.out.println("===B b1 = (B)a;: ==="); /* Exception in thread "main" java.lang.ClassCastException: com.cl251ka.demo005.A cannot be cast to com.cl251ka.demo005.B at com.cl251ka.demo005.DuoTai.main(DuoTai.java:25)*/ // B b1 = (B)a; ---->a强转为B后,大于a范围部分无法接收,故运行时出错 // b1.printA(); // b1.printB(); System.out.println("===B b2 = (B)a1;: ==="); // AB方法均调用成功 // 因为a1是由B类型强转过来的,本身带有B大于a的部分,只是由于强转没有使用,此时转回B类型又可以使用了 B b2 = (B)a1; b2.printA(); b2.printB(); } }
此时可以很清楚地看到
` A a1 = new B();
a1.printA();
!// a1.printB(); //报错了`
这一部分用 a 引用直接 new 了 B 对象直接成功了,是因为此时有一个自动类型转换:
A a1 = (A) new B(); (应该是这样的,子类转父类自动进行了)
而从方法的调用可以看出,此时虽然创建了B对象,但是B中的方法还是调用不了,通俗一点来说就是在自动转换时给了一个B的内存空间,却只让a1访问a那么大的部分,所以能调用A的方法却不能调用B的方法。
(注意此处的内存空间的说法并不严谨,只是为了方便理解这么说的)
结合
B b2 = (B)a1;
b2.printA();
b2.printB();
看,此时将a1强转成B类型时,B方法又能调用了,而
// B b1 = (B)a; ---->a强转为B后,大于a范围部分无法接收,故运行时出错
// b1.printA();
// b1.printB();
直接对 a 强转时却在运行时报错了,这是因为 a 是直接由 A a = new A();
得到的,而此时 A 作为 B 的父类,强行给它转换成B类型在运行时出现了 类型转换( ClassCastException )异常 ,其实可以用 instanceof 解除该风险。
总结:
向上转型:子类转父类可以自动进行,但转换后只能调用父类中原有的属性和方法
向下转型:父类转子类必须显示(强制)进行,而且转换后在运行时有出现类型转换异常的风险
(但如果是从B转到A再转到B的话,还是可以使用A 和 B中的所有的方法的)
================================================
随后发现了自己踩的一个坑:
父类引用指向子类对象其实是JAVA多态的一种体现,其实并不是说子类的方法就不能用了而是需要重写再使用,至于这样有什么好处,,,好处就在于JAVA中一个父类可以有很多子类,而每个子类都可能有自己独特的某方法,这样在用多态的思想创建对象时可以很方便地找到对应的子类,知道这个子类中独有的方法需要如何实现就可以直接重写该方法,不需要再写这个类的其他方法了。
至于标题上的强转问题,只是遇到了然后想了想,了解一下就好。
00:09,睡了