向上转型与向下转型(超详细)

本文利用代码例子解释向上转型与向下转型,文末有举例整合原代码。


首先,我们要知道:转型发生在继承后,也就是父类子类存在的前提下。其次,我们要清楚:向下转型的前提是已经发生了向上转型,向下转型是再次转回来而已。最后,我们要明白:向上转型和向下转型都有三种方法:直接赋值、作为参数和作为返回值类型。另外,我们要注意:向下转型要用到强制类型转换,从而完成接收。


定义三个类:Animals 类、NiuMa 类、A 类:

class Animals{  //Animals类,作为父类
    public void eat1(){
        System.out.println("几乎都是肉食动物");
    }
}

class NiuMa extends Animals{   //NiuMa类:作为子类
    public void eat2(){
        System.out.println("杂食动物");
    }
    public void sleep(){
        System.out.println("都要睡觉。");
    }
}

class A{    //A类:作为参数和返回类型要用到。
    public void func1(Animals animals){
        animals.eat1();
        System.out.println("父类形参");
    }
    public void func3(NiuMa niuMa){
        niuMa.sleep();
        System.out.println("子类形参");
    }

    public NiuMa func2(){
        System.out.println("此时返回值类型与public后的引用类型一致");
        return new NiuMa();
    }   
    public Animals func4(){
        System.out.println("此时返回值类型与public后的引用类型不一致!");
        return new NiuMa();
    }
    public Animals func5(){
        System.out.println("此时返回值类型与public后的引用类型一致");
        return new Animals();
    }
    public NiuMa func6(){
        System.out.println("此时返回值类型与public后的引用类型不一致!");
        return (NiuMa)new Animals();
    }
}

Animals 类:作为父类,具有公共方法 eat1() 。

NiuMa 类:作为子类,具有子类独有方法 sleep() 。

A 类:作为其他类,要借助该类实现参数类型和返回值类型的转型。


向上转型:

一、直接赋值法:

class Text{
   public static void main(String[] args) {
         Animals people1 = new NiuMa();
         people1.eat1();//调用继承后公共部分的方法,没重写调用没重写的,重写了调用重写后的。
   }
}

父类引用子类对象:Fu dui1 = new Zi();

可用该对象调用继承后公共部分的方法,若该方法被子类重写,则调用重写后的方法

二、作为参数法:

class Text{
   public static void main(String[] args) {
        NiuMa niuma1 = new NiuMa();
        A a1 = new A();
        a1.func1(niuma1);
   }
}

形参为父类,实参为子类。

在方法中实现向上转型,即在 func 方法中已经完成转型任务,完成调用其他方法的实现。

三、作为返回值类型法:

class Text{
   public static void main(String[] args) {
        //返回值类型法向上转型:

        //利用func2():public后面为子类,返回值类型为子类
        A a1 = new A();
        //用引用类型直接接收:
        NiuMa niuma1 = a1.func2();//正常接收。
        Animals animals1 = a1.func2();//发生了向上转型
        //new对象进行接收:
        NiuMa niuma2 = new NiuMa();
        Animals animals2 = new Animals();
        niuma2 = a1.func2(); //正常接收
        animals2 = a1.func2();//发生了向上转型

        //利用finc4():public后面为父类,返回值类型为子类
        A a2 = new A();
        //用引用类型直接接收:
        NiuMa niuma3 = (NiuMa) a2.func4();//相当于发生了一次向下转型
        Animals animals3 = a2.func4();//正常接收。
        //new对象进行接收:
        NiuMa niuma4 = new NiuMa();
        Animals animals4 = new Animals();
        niuma4 = (NiuMa) a2.func4(); //相当于又发生了一次向下转型。
        animals4 = a2.func4();//正常接收

        //结论:当public后面为父类,返回值为子类时,实际返回值为父类类型。

   }
}

此块代码主要看利用 func2() 的,因为返回值类型参考的是 public 后为父类还是子类。

父类引用,接收返回类型为子类的方法,实现向上转型。


向下转型:

一、直接赋值法:

class Text{
   public static void main(String[] args) {
        Animals people2 = new NiuMa();//要先发生一次向上转型
        NiuMa people3 = (NiuMa) people2; //将people2强制类型转换成NiuMa类,用people3接收
        people1.eat1();
        people3.sleep();
   }
}

要先发生向上转换:Fu dui2 = new Zi();

向下转换:Zi dui3 = (ZI) dui3;

二、作为参数法:

class Text{
   public static void main(String[] args) {
        Animals animals1 = new NiuMa();//先发生强制类型转换
        A a2 = new A();
        a2.func3((NiuMa) animals1);
   }
}

形参为子类,实参为父类。

在方法中实现向下转型,即在 func 方法中已经完成转型任务,完成调用其他方法的实现。

传参时要进行强制类型转换。

三、作为返回值类型法:

public Text{
    public static void main(String[] args) {
        //返回值类型法向下转型:

        //利用func5():public后面为父类,返回值类型为父类。
        A a1 = new A();
        //用引用类型直接接收:
        NiuMa niuma1 = (NiuMa) a1.func5();//发生了向下转型
        Animals animals1 = a1.func5();//正常接收
        //new对象进行接收:
        NiuMa niuma2 = new NiuMa();
        Animals animals2 = new Animals();
        niuma2 = (NiuMa) a1.func5();//发生了向下转型
        animals2 = a1.func5();//正常接收

        //利用func6():public后面为子类,返回值类型为父类。
        A a2 = new A();
        //用引用类型直接接收:
        NiuMa niuma3 = a2.func6();//正常接收
        Animals animals3 = a2.func6();//相当于向上转型
        //new对象进行接收:
        NiuMa niuma4 = new NiuMa();
        Animals animals4 = new Animals();
        niuma4 = a2.func6(); //正常接收
        animals4 = a2.func6();//相当于向上转型

        //小结:当public后面为子类,返回值类型为父类的时候,返回值类型为子类。
    }
}

此块代码主要看利用 func5() 的,因为返回值类型参考的是 public 后为父类还是子类。

子类引用,接收返回类型为父类的方法,实现向上转型,要注意进行强制类型转换。


注意点:

一、以下为错误代码:

class Text{
   public static void main(String[] args) {
        //⭐错误代码:
        Animals people = new Animals();
        A a = new A();
        a.func3(people);
        //形参只能向下兼容,不能向上兼容。向下兼容的时候传入子类则会发生向上转型。
   }
}

此时代码直接会报错:

因为该代码与是否发生向上转型或向下转型无关。而向下转型的本质是已经发生过向上转型,通过强制类型转换从而回来罢了,但是该处错误直接类型不匹配。

由此我们也可以得出一个结论:

形参只能向下兼容,不能向上兼容。向下兼容的时候传入子类则会发生向上转型。

二、关于返回值类型同方法上下不匹配:

在 func4() 与 func6() 中,public 后的引用类型与返回值类型不匹配,但在主函数中用某引用类型去接收该返回值的时候,一定要用 pubic 后的引用类型

三、为什么会发生向上转型和向下转型?

向上转型是为了调用父类中的方法,向下转型是为了使用完后转回子类,以此才能调用父类中没有的方法


总结:

向上转型:自动转型,父类引用子类对象。for调父类方法。

向下转型:强制类型转换,本质上就是子类已经发生了向上转型,再次转回来而已。for调父类中没有的子类方法。


以下为整合代码:

放入 Idea 里分别把 main 方法放开运行理解更深刻:

class Animals{
    public void eat1(){
        System.out.println("几乎都是肉食动物");
    }
}
class NiuMa extends Animals{
    public void eat2(){
        System.out.println("杂食动物");
    }
    public void sleep(){
        System.out.println("都要睡觉。");
    }
}
class A{
    public void func1(Animals animals){
        animals.eat1();
        System.out.println("父类形参");
    }
    public void func3(NiuMa niuMa){
        niuMa.sleep();
        System.out.println("子类形参");
    }

    public NiuMa func2(){
        System.out.println("此时返回值类型与public后的引用类型一致");
        return new NiuMa();
    }
    public Animals func4(){
        System.out.println("此时返回值类型与public后的引用类型不一致!");
        return new NiuMa();
    }

    public Animals func5(){
        System.out.println("此时返回值类型与public后的引用类型一致");
        return new Animals();
    }
    public NiuMa func6(){
        System.out.println("此时返回值类型与public后的引用类型不一致!");
        return (NiuMa)new Animals();
    }

}
public class ZhuAn {
    public static void main4(String[] args) {//主要为向下转型。
        //返回值类型法向下转型:

        //利用func5():public后面为父类,返回值类型为父类。
        A a1 = new A();
        //用引用类型直接接收:
        NiuMa niuma1 = (NiuMa) a1.func5();//发生了向下转型
        Animals animals1 = a1.func5();//正常接收
        //new对象进行接收:
        NiuMa niuma2 = new NiuMa();
        Animals animals2 = new Animals();
        niuma2 = (NiuMa) a1.func5();//发生了向下转型
        animals2 = a1.func5();//正常接收

        //利用func6():public后面为子类,返回值类型为父类。
        A a2 = new A();
        //用引用类型直接接收:
        NiuMa niuma3 = a2.func6();//正常接收
        Animals animals3 = a2.func6();//相当于向上转型
        //new对象进行接收:
        NiuMa niuma4 = new NiuMa();
        Animals animals4 = new Animals();
        niuma4 = a2.func6(); //正常接收
        animals4 = a2.func6();//相当于向上转型

        //小结:当public后面为子类,返回值类型为父类的时候,返回值类型为子类。
    }
    public static void main3(String[] args) {//主要为向上转型:
        //返回值类型法向上转型:

        //利用func2():public后面为子类,返回值类型为子类
        A a1 = new A();
        //用引用类型直接接收:
        NiuMa niuma1 = a1.func2();//正常接收。
        Animals animals1 = a1.func2();//发生了向上转型
        //new对象进行接收:
        NiuMa niuma2 = new NiuMa();
        Animals animals2 = new Animals();
        niuma2 = a1.func2(); //正常接收
        animals2 = a1.func2();//发生了向上转型

        //利用finc4():public后面为父类,返回值类型为子类
        A a2 = new A();
        //用引用类型直接接收:
        NiuMa niuma3 = (NiuMa) a2.func4();//相当于发生了一次向下转型
        Animals animals3 = a2.func4();//正常接收。
        //new对象进行接收:
        NiuMa niuma4 = new NiuMa();
        Animals animals4 = new Animals();
        niuma4 = (NiuMa) a2.func4(); //相当于又发生了一次向下转型。
        animals4 = a2.func4();//正常接收

        //结论:当public后面为父类,返回值为子类时,实际返回值为父类类型。

    }

    public static void main2(String[] args) {
        //传参法:在方法内实现向上转型,在方法内调用方法。

        //向上转型:
        NiuMa niuma1 = new NiuMa();
        A a1 = new A();
        a1.func1(niuma1);

        //向下转型:
        Animals animals1 = new NiuMa();//先发生强制类型转换
        A a2 = new A();
        a2.func3((NiuMa) animals1);

        //⭐错误代码:
        //Animals people = new Animals();
        //A a = new A();
        //a.func3(people);
        //形参只能向下兼容,不能向上兼容。向下兼容的时候传入子类则会发生向上转型。
    }

    public static void main1(String[] args) {
        //直接赋值法

        //向上转型
        Animals people1 = new NiuMa();
        people1.eat1();//调用继承后公共部分的方法,没重写调用没重写的,重写了调用重写后的。

        //向下转型
        Animals people2 = new NiuMa();//要先发生一次向上转型
        NiuMa people3 = (NiuMa) people2; //将people2强制类型转换成NiuMa类,用people3接收
        people1.eat1();
        people3.sleep();
    }
}

  • 18
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值