Java的向上转型和向下转型

一、向上转型(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);
    }
}

结论=》上转型对象通过重写的方法会调用继承的变量,通过“.”来直接访问隐藏的变量,未被重写的方法则会调用隐藏的变量

 

posted @ 2020-11-29 15:00  何梦吉他  阅读(365)  评论(0编辑  收藏  举报