Java(转发) Java子类与父类之间的靶子转换

  在拔取Java的多态机制时,平日使用的一个特性便是子类和父类之间的靶子转换。从子类向父类的变换称为向上转换(upcasting),通过进步转换,大家可以在编写程序时行使通用程序设计的思索,在必要使用子类对象的时候,通过把变量定义为父类型,大家得以经过一个变量,使用该父类型的所有子类型实例;从父类型向子类型的转移称为向下转移(downcasting),通过向下更换,大家能在必要的时候,将父类型变量转换成子类型变量,使用一些经过子类型才可以运用的法子。以下是本人对此目的转换的一些私有精通,如有不对,欢迎指正,虚心向大神们请教。

  首先是从子类向父类的腾飞转换。向上转换比较直观,总是可以将一个子类的实例转换为一个父类的目的,从继承链的角度,这些特性很简单通晓:继承是一种“是一种”的关联,从父类派生出的子类,大家都能分晓为,子类总是父类的一个实例。比如说,Fruit类派生出了Orange类,Apple类,Orange和Apple都是Fruit;Animal类派生出了Tiger类和Lion类,Tiger和Lion都是Animal。因而,从子类向父类的转换不需求什么范围,只需直接将子类实例赋值给父类变量即可,那也是Java中的多态的兑现机制。

//Test.java
public class Test {
    public static void main(String args[]) {
        Animal tiger = new Tiger();
        Animal lion = new Lion();
    }
}

class Animal {
    String name;
    Animal() {
        name = "animal";
    }
    Animal(String name) {
        this.name = name;
    }
}
class Tiger extends Animal {
    Tiger() {
        super("tiger");
    }
}
class Lion extends Animal {
    Lion() {
        super("lion");
    }
}

  

  可是从父类向子类的向下更换就有些复杂一些了。在讲述向下更换此前,也许有点刚学java的爱侣会有点茫然为啥要运用向下更换,使用多态和动态绑定机制通过父类型变量使用子变量不就足以了么(比如我就曾对此感到疑心)。那即将考虑到,在两次三番关系中,有一对办法是不适合由父类定义并由子类继承不分厚薄写的,有些措施是子类特有的,不该通过持续取得,且子类可能也会有协调故意的成员变量,那么在选取多态机制的时候,若大家要因而父类型变量使用到这么些子类特有的措施和性质的话,就必要将服类型变量转换成对应的子类型变量。一个卓绝例子便是标准库中的数据类型包装类:Integer类,Double类,Long类等,它们都继承自Number类,且它们都有一个方法叫做compareTo用于相比多个一样的花色。不过那几个艺术是这么些子类通过落到实处Comparable接口来兑现的,在Number类中并没有该方式的得以落成,由此若要通过Number类型变量来使用compareTo方法,就要先将Number类转换成子类的靶子。

  从父类向子类的转移就有限制了。首先,父类变量向子类转换必须经过显式强制类型转换,选用和升华转换相同的一向赋值格局是特其他,;并且,当把一个父类型变量实例转换为子类型变量时,必须有限支持该父类变量是子类的一个实例,从继承链的角度来了解这么些原因:子类一定是父类的一个实例,可是父类却不自然是子类的实例;比如说,Fruit未必是Orange,它恐怕是Apple;Animal也不必然是Tiger,它可能是Lion。用代码来解释一下:

Animal tiger = new Tiger();
Animal lion = new Lion();

  在前头向上转换的代码示例当中,main方法中的这两行代码,意思就是父类型变量tiger是子类Tiger的一个实例,lion是Lion的一个实例。 
  也就是说,如果要把tiger转换为Tiger类型,必须保险tiger本身是Tiger的一个实例,在上例中,借使要把tiger转换成Lion类型,或是把Lion类型转换为Tiger类型,都是不行的,在运行时,那会抛出一个周转十分ClassCastException,表示类转换至极。由此,在开展父类向子类的更换时,一个好的习惯是经过instanceof运算符来判断父类变量是否是该子类的一个实例:

  

Tiger t = null;
if(tiger instanceof Tiger)
    t = (Tiger)tiger;

  要是要通过父类调用子类变量的办法,那么要小心要将父类型变量和强制转换用括号括起来:

Number i = new Integer(3);
System.out.println(
    ((Integer)i).compareTo(new Integer(4))
                  );

  因为成员访问运算符.的先期级大于类型转换,所以要用括号括起来有限支撑类型转换先于成员访问举办演算。 
  后边说到用instanceof判断父类是否是子类的一个实例是一个好习惯,即使不养成这一个习惯的话很简单出题目,请看上面那段代码:

Animal animal = new Tiger();
Lion lion = (Lion)tiger;

  前面说到,那段代码会在运转时抛出ClassCastException分外,然则,那段代码却是可以编译成功的。原因是因为,Java编译器并从未灵气到可以在编译阶段就清楚父类型变量是哪一个子类的实例,所以,将animal转换为Lion类型的代码:(Lion)animal是力所能及编译通过的,固然实际大家能观察animal是Tiger的一个实例,因为Animal类型确实能转换成Lion类型,所以那条语句是官方的。所以,假诺没有采纳instanceof幸免分裂子类型之间的目的转换,而又不可以指望编译器检查出这种转移逻辑错误的话,就很不难犯错了。

相关文章