Java向上下转型中的陷阱{详细}
1: 多态
多态时继承下面的产物,之所以存在向上向下转型的目的,就是解决参数传递的不变形,体现面向接口编程的重要性,
1.1 方法的多态性
①. 方法的重载:同一个方法名称可以根据参数的类型或个数不同调用不同的方法体。
②. 方法的覆写:同一个父类的方法,可能根据实例化子类的不同也有不同的表现形式。
1.2. 对象的向上转型
出现了父类指向了子类那么出现 向上转型 对象的向上转型:父类 父类对象 = 子类实例
class Person{ public void say() { System.out.println("我是Person"); } } public class Student extends Person { public void say() { System.out.println("我是Student"); } public void gotoSchool() { System.out.println("我的职责是上学"); } public static void main(String[] args) { // 向上转型 父类实例对象指向子类实例 只保留父类子类同名的方法,且子类变量覆盖父类变量 Person p=new Student(); p.say(); } }
输出: 我是Student
目的: 用于参数统一化,假设父类有n个子类,方法要接受子类的实例,如果没有向上转型,就需要定义n个方法接收不同的对象
1.3 对象的向下转型
对象的向下转型:子类 子类对象 = (子类)父类实例
class Person{ public void say() { System.out.println("我是Person"); } } public class Student extends Person { public void say() { System.out.println("我是Student"); } public void gotoSchool() { System.out.println("我的职责是上学"); } public static void main(String[] args) { // 向上转型 父类实例对象指向子类实例 只保留父类子类同名的方法,且子类变量覆盖父类变量 Person p=new Student(); p.say(); // 向下转型 子类实例指向父类 可以拥有子类自己的方法, Student s=(Student) p; s.say(); s.gotoSchool(); } }
注意: 向下转型之前一定要进行向上转型!!(让父类先指向子类)
否则在转型时会出现ClassCastException(类型转换异常–运行时异常)
问题: 如果向下转型存在安全隐患,那么如何转型才靠谱
class Person{ public void print() { System.out.println("我是人"); } public void p() { System.out.println("伤心的一天"); } } class Student extends Person{ public void print() { System.out.println("我是学生"); } public void fun() { System.out.println("开心的一天!"); } } public class Test{ public static void main(String[] args) { Person per = new Student(); //per是否能表示Person实例 System.out.println(per instanceof Person); //per是否能表示Student实例 System.out.println(per instanceof Student); if(per instanceof Student) { Student stu = (Student)per; stu.fun(); } } }
注意: 虽然增强了 程序的健壮性 但是,仅仅是这样,你还是需要 在这之前 进行 父类指向子类实例的过程 父类 父类对象 = 子类实例
1,4 扩展调用的例子
class Person{ public void print() { System.out.println("我是人"); } } class Student extends Person{ public void print() { System.out.println("我是学生"); } } class Worker extends Person{ public void print() { System.out.println("我是工人"); } } public class Test{ public static void main(String[] args) { whoAreYou(new Student()); whoAreYou(new Worker()); } public static void whoAreYou(Person per) { per.print(); } }
2: 存在公共变量的分析过程
先类看一个代码:
class BB{ public String S="B"; public String getS() { return this.S; } public void setS(String s) { this.S = s; } } public class AA extends BB{ public String S="A"; public String getS() { return this.S; } public void setS(String s) { this.S = s; } public static void main(String[] args) { AA aa = new AA(); BB bb = new BB(); System.out.println(aa.S); System.out.println(bb.S); aa.setS("AA"); bb.setS("BB"); System.out.println(bb.S); bb=aa; aa=(AA) bb; System.out.println(bb instanceof BB); System.out.println(bb instanceof AA); System.out.println(aa.S); System.out.println(bb.S); System.out.println(aa.getS()); System.out.println(bb.getS()); System.out.println(bb.S); } }
一般我们认为输出
1:A 2:B 3:BB 4:true 5:true 6:AA 7:BB 8:AA 9:AA 10:BB
上面输出 前6个没有问题,第七个由于前面执行了B.setS 所以我们认为应该为BB
正确输出结果为:
1:A 2:B 3:BB 4:true 5:true 6:AA 7:B 8:AA 9:AA 10:B
那么为什么我们 第 7 10输出结果为 B呢, 我们打上断点看一下:
1: aa实例 由于继承了bb 所以域中存在S='B'
当执行了 设置BB的时候, 值按照我们的意思改变了
当执行了向上转型的时候,AA指向父类的实例,所以发生改变
所以第 System.out.println(bb.S); 能够输出 B,
而 System.out.println(bb.getS());为什么输出AA 因为当前指向指向子类 aa aa中的getS方法与父类同名,那么执行子类的方法,注意:如果这里为不同名称的方法,那么执行父类的方法,
我给出这个代码:
package LL; class BB2{ public int SB=1; public int getSB() { return SB; } public void setSB(int sB) { SB = sB; } } public class PP extends BB2{ public int SA=2; public int getSA() { return SA; } public void setSA(int sA) { SA = sA; } public static void main(String[] args) { PP aa = new PP(); BB2 bb = new BB2(); System.out.println(aa.SA);//2 System.out.println(bb.SB);//1 aa.setSA(22); bb.setSB(11); System.out.println(bb.SB);//11 bb=aa; System.out.println(bb instanceof BB2); System.out.println(bb instanceof PP); System.out.println(aa.SA);//22 System.out.println(bb.SB);//1 System.out.println(aa.getSA());//22 System.out.println(bb.getSB());//22 System.out.println(bb.SB);//1 } }
3:总结
- 最好将变量private 私有化 ,以免阅读程序麻烦
- 存在public变量时候,继承的子类 执行的时候 回拷贝一份父类的变量,(表示 父类修改变量不会影响子类拷贝这个变量的值)
- 当发生向上转型的时候,父类指向子类实例,那么父类实例拥有与子类实例一样的参数变量,
- 转型的时候 子类只会保留与父类中同名的方法,其他放弃
- 最后: 向下转型的时候 ,一定必须让父类实例指向子类