一、向上转型(upcasting) 、向下转型(downcasting)。
举个例子:有2个类,Father 是父类,Son 类继承自 Father。
第 1 个例子:
Father f1 = new Son(); // 这就叫 upcasting (向上转型) // 现在 f1 引用指向一个Son对象 Son s1 = (Son)f1; // 这就叫 downcasting (向下转型) // 现在f1 还是指向 Son对象
第 2 个例子:
Father f2 = new Father(); Son s2 = (Son)f2; // 出错,子类引用不能指向父类对象
你或许会问,第1个例子中:Son s1 = (Son)f1; 问为什么是正确的呢。
很简单因为 f1 指向一个子类对象,Father f1 = new Son(); 子类 s1 引用当然可以指向子类对象 Son s1 = (Son)f1;
而 f2 被传给了一个 Father 对象,Father f2 = new Father(); 子类 s2 引用不能指向父类对象 Son s2 = (Son)f2;
总结:
1、父类引用指向子类对象,而子类引用不能指向父类对象。
2、把子类对象直接赋给父类引用叫upcasting向上转型,向上转型不用强制转换吗,如:Father f1 = new Son();
此时通过父类引用变量调用的方法是子类覆盖或继承 父类的方法,不是父类的方法。
此时通过父类引用变量无法调用子类特有的方法。
3、把指向子类对象的父类引用赋给子类引用叫向下转型(downcasting),要强制转换,如:f1 就是一个指向子类对象的父类引用。把f1赋给子类引用 s1 即 Son s1 = (Son)f1;其中 f1 前面的(Son)必须加上,进行强制转换。
参考:https://www.cnblogs.com/xiaoyezideboke/p/10939219.html
二、向上转型的作用
https://blog.csdn.net/guchenjun789/article/details/81055317 写的不错!!
三、向上转型调用静态方法时的注意点
比较下面代码输出结果(实际开发中不会遇到,只是在找工作时可能会遇到)
非static方法
public class StaticTest { public static void main(String[] args) { Parent p = new Child();//向上转型 p.output(); } } class Parent { public void output() { System.out.println("Parent"); } } class Child extends Parent { public void output() { System.out.println("Child"); } }
输出结果为:Child
static方法
public class StaticTest { public static void main(String[] args) { Parent p = new Child(); p.output(); } } class Parent { public static void output() { System.out.println("Parent"); } } class Child extends Parent { public static void output() { System.out.println("Child"); } }
输出结果为:Parent
为什么加static修饰方法后结果就变不一样了呢? ???
子类可以继承父类的静态方法,但是子类不能重写父类的静态方法。在这种情况下子类怎么办呢,子类隐藏(术语hidden)了父类的静态方法,因为子类没法重写,所以当p是Parent引用类型时,调用的就是Parent类里的output()方法,而不是Child类里的output()方法,因为Child类里没有重写output()方法,意思等价于Child类里根本没有父类版本的output()方法(Child里的output和Parent里的output方法是不同的方法,这样理解)。
如下代码可以证明子类没有重写父类静态方法(方法是加上@Override表示要重写,但是会编译报错)。
public class StaticTest { public static void main(String[] args) { Parent p = new Child(); p.output(); } } class Parent { public static void output() { System.out.println("Parent"); } } class Child extends Parent { //加上注解后编译会报错,证明子类没有重写父类方法,若去掉static,编译不会报错 @Override public static void output() { System.out.println("Child"); } }
编译结果如下:
StaticTest.java:20: 错误: 方法不会覆盖或实现超类型的方法
@Override
^
1 个错误
四、向上转型中成员变量的调用
第一个例子
class A{ int m; int getM(){ System.out.printf("A中getM "); return m; } int seeM(){ System.out.printf("A中seeM "); return m; } void setM(int m){ this.m = m; } } class B extends A{ int m; int getM(){ System.out.printf("B中getM "); return 100+m; } void setM(int m){ this.m = m; } int seeM(){ System.out.printf("B中seeM "); return m+1; } } public class E{ public static void main(String args[]){ B b = new B(); b.setM(20); b.m = 20; System.out.println(b.getM());//B中getM 120 A a = b; a.setM(-50);//对B类的成员变量赋值,此时b.m=-50 a.m = -100;//对A类的成员变量赋值!此时a.m=-100 注意和a.setM区别 System.out.println(a.getM());//B中getM 50 System.out.println(b.seeM());//B中seeM -49 System.out.println(a.m); System.out.println(b.m); } }
如果B类不重写setM和getM方法,即:
//class A{ // int m; // int getM(){ // System.out.printf("A中getM "); // return m; // } // int seeM(){ // System.out.printf("A中seeM "); // return m; // } // void setM(int m){ // this.m = m; // } //} // //class B extends A{ // int m; // int getM(){ // System.out.printf("B中getM "); // return 100+m; // } // void setM(int m){ // // this.m = m; // } // int seeM(){ // System.out.printf("B中seeM "); // return m+1; // } //} // //public class E{ // public static void main(String args[]){ // B b = new B(); // b.setM(20); // b.m = 20; // System.out.println(b.getM());//B中getM 120 // A a = b; // // a.setM(-50);//对B类的成员变量赋值,此时b.m=-50 // a.m = -100;//对A类的成员变量赋值!此时a.m=-100 注意和a.setM区别 // System.out.println(a.getM());//B中getM 50 // System.out.println(b.seeM());//B中seeM -49 // System.out.println(a.m); // System.out.println(b.m); // } //} class A{ int m; int getM(){ System.out.printf("A中getM "); return m; } int seeM(){ System.out.printf("A中seeM "); return m; } void setM(int m){ this.m = m; } } class B extends A{ int m; int seeM(){ System.out.printf("B中重写的seeM "); return m+1; } int seeM2(){ System.out.printf("B中新增的see2M "); return super.m; } } public class E{ public static void main(String args[]){ B b = new B(); b.setM(20);//设置A类的成员变量【隐藏变量】,setM方法未被重写,B类直接继承A类的setM方法 System.out.println(b.m);//0! System.out.println(b.seeM());//1 System.out.println(b.seeM2());//20 A a = b; a.setM(-50);//设置A类的成员变量【隐藏变量】 //a.m = -100; System.out.println(a.getM());//-50 System.out.println(b.seeM());//1 System.out.println(a.m); System.out.println(b.m); } }
结论=》上转型对象通过重写的方法会调用继承的变量,通过“.”来直接访问隐藏的变量,未被重写的方法则会调用隐藏的变量