JAVA面向对象-向上、向下转型(8)


:::tips
父类引用指向子类对象,则称为向上转型(upcasting)一般称为自动类型转换
子类引用指向父类对象,称为向下转型(downcasting)一般用于子类中特有的方法,才用下转型这个父类对象是子类向上转型而来,则安全,反之不安全,避免不安全向下转型的方法是先用isntanceof运算符判断向下转型的对象是不是向下转型的目标对象。
个人助记方法: 将父类对象赋值给子类引用,那么是往下走,那么就是向下转型;那么反之,将子类对象赋值给父类引用,那么就是向上走,就是向上转型。
:::

定义三个类: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);
        //形参只能向下兼容,不能向上兼容。向下兼容的时候传入子类则会发生向上转型。
   }
}

此时代码直接会报错
image.png
因为该代码与是否发生向上转型或向下转型无关。而向下转型的本质是已经发生过向上转型,通过强制类型转换从而回来罢了,但是该处错误直接类型不匹配。
由此我们也可以得出一个结论:
形参只能向下兼容,不能向上兼容。向下兼容的时候传入子类则会发生向上转型。
二、关于返回值类型同方法上下不匹配:
在 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();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leoon123

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值