Java向上向下转型那些事

在学习Java编程中,最头疼事情之一就是数据类型转换。有时候它在不经意之间就完成了(自动类型转换),有时候却又要求我们手动指定(强制类型转换)。基本数据类型,转换规则还可以通过类型本身空间大小和精度分析明白,而且最多就是丢失精度,运行起来至少是不会报错。可是面对引用数据类型,这个“坑”就大了:有自动转的,有强制转的,还有强制都转不了的;自动转了的却把对象身上的方法丢了看不见;强制转的编译过了运行却可能报异常。
笔者也是花了好久才勉强弄懂,分享本文帮助读者理解

一、转型(casting):

首先我们来了解转型的定义:
1、向上转型(upcasting):子–>父(自动类型转换)
2、向下转型(downcasting):父–>子(强制类型转换,需要加转换符)

上述两点前提:必须要有继承关系!

二、定义类:

我们首先定义一个Animal类:

package JavaseTest01;

public class Animal extends Object {

    public void move() {
        System.out.println("动物在移动");
    }
}

再定义一个Cat类:

package JavaseTest01;

public class Cat extends Animal {

    //重写父类中继承的方法
    public void move() {
        System.out.println("猫在走猫步");
    }
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

再定义一个Bird类:

package JavaseTest01;

public class Bird extends Animal {

    public void move() {
        System.out.println("鸟儿在飞翔");
    }

    public void fly() {
        System.out.println("Bird fly");
    }
}

三、向上转型(upcasting):

猫一定是动物,但动物不一定是猫:

package JavaseTest01;

public class Test01 {

    public static void main(String[] args) {
    
        Animal a2 = new Cat();//向上转型
        a2.move();
        c2.catchMouse();
  }
}

如上代码,这里new的实际上是一个Cat对象,程序在运行阶段一定会调用,这就叫向上转型。
Cat对象的move方法。a2这个引用数据类型为Animal,由于Animal.class中有move方法,故编译通过。

四、向下转型(downcasting):

1、问题提出:

但是,如果对象调用的方法是父类中没有的,(比如调用catMouse方法),会报错。
所以这里就要用到强制类型转换(向下转型)。

2、向下转型:

可以将a2强制类型转化为Cat类型
A2的类型是Animal(父类),转换成Cat类型(子类),被称为向下转型

package JavaseTest01;

public class Test01 {

    public static void main(String[] args) {
    
        Animal a2 = new Cat();//向上转型
        a2.move();
        Cat c2 = (Cat) a2;
        c2.catchMouse();
  }
}

如上代码,把原本是Animal的引用数据类型a2转换成了Cat的引用数据类型,这样就可以调用Cat中的catchMouse方法了(类比int i=(int)x)

3、问题1:

(1)问题提出:

如果这个Java包中的Test程序这样写:

package JavaseTest01;

public class Test01 {

    public static void main(String[] args) {
    
        Animal a3 = new Bird();
        Cat c3 = (Cat) a3;
  }
}

上述代码在编译阶段不会报错,但是在运行阶段报错,为什么?

(2)问题分析:

(1)首先,程序编译没有问题,因为编译器检测到a3的数据类型是Animal,因为Animal和Cat之间存在继承关系,且Animal是父类型,Cat是子类型,父类型转换成子类型,向下转型语法合格。
(2)程序虽然编译通过了,但是程序在运行阶段会出现异常,因为JVM堆内存中真实存在的对象是Bird类型,Bird对象无法转换为Cat对象,Bird和Cat之间不存在继承关系,这就是著名的异常:Java.lang.ClassCastException(类型转换异常)

4、问题2:

(1)问题提出:

如果代码这样写:

package JavaseTest01;

public class Test02 {

    public static void main(String[] args) {

        //子类指向父类
        Animal a4 = new Animal();
        Cat c4 = (Cat) a4;
  }
}

上述代码运行阶段仍然不会报错,但在运行阶段会报错,为什么?

(2)问题分析:

(1)首先,程序编译没有问题,因为编译器检测到a4的数据类型是Animal,因为Animal和Cat之间存在继承关系,且Animal是父类型,Cat是子类型,父类型转换成子类型,向下转型语法合格。
(2)程序虽然编译通过了,但是程序在运行阶段会出现异常,因为a4是Animal这个父类对象的数据类型,而c4指向的是子类对象Cat,子类对象不能指向父类对象,该异常遇上个问题相同:Java.lang.ClassCastException(类型转换异常)

五、向下转型的问题解决:

为了解决以上问题,我们引入一个关键字-----instanceof
instanceof运算符执行结果类型是布尔类型,结果可能是true/false
假设:(a instanceof Animal)
true:a这个引用指向的对象是一个Animal类型
false:a这个引用指向的对象不是一个Animal类型

package JavaseTest01;

public class Test01 {

    public static void main(String[] args) {

        //解决方式:
        Animal a3 = new Bird();
        if(a3 instanceof Cat) {
            Cat c3 = (Cat) a3;
            c3.catchMouse();
        } else if(a3 instanceof Bird) {
            Bird b2 = (Bird)a3;
            b2.fly();
        }
    }
}

在Java编程规范中,我们建议在强制类型转换之前采用instanceof运算符进行判断,避免因为对象指向不明而产生错误。

六、总结:

1、在引用数据类型中,只有有继承关系的类型才能进行类型转换;
类型转换只是转换看待对象的引用的类型,对象本身没有也不可能参与转换;
2、父类引用可以自动指向子类对象,但只能访问和调用到来自于父类的属性和行为;
3、子类的引用不能指向父类或其它子类对象,就算强转也会导致运行失败并抛出ClassCastException;
3、把父类引用赋给子类引用,语法上必须使用强制类型转换,要想运行也成功还必须保证父类引用指向的对象一定是该子类对象(最好使用instance判断后,再强转)

  • 21
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值