一.向上转型
向上转型其实就是创建一个子类对象,并将其当作父类对象来使用,一般语法格式如下:
父类类型对象名 = new 子类类型()
一般有以下三种使用场景:
直接赋值
我们这里以父类为Animal类举例,并且有一个Cat类来继承他
class Animal { String name; int age; //构造方法 public Animal(String name,int age) { this.name = name; this.age = age; } public void eat() { System.out.println(this.name + "正在吃食物~~~"); } } class Cat extends Animal { //构造方法 public Cat(String name,int age) { super(name,age); } }
在这种情况下,我们用父类对象直接引用子类对象,不但程序不会报错,反而还可以正常调用父类中的成员方法
public static void main(String[] args) { Cat cat = new Cat("布偶",3); Animal animal1 = cat; animal1.eat(); Animal animal2 = new Cat("橘猫",2); animal2.eat(); }
输出结果:
那能不能调用子类的成员方法呢?我们在子类中新添加一个sleep方法
class Animal { String name; int age; //构造方法 public Animal(String name,int age) { this.name = name; this.age = age; } public void eat() { System.out.println(this.name + "正在吃食物~~~"); } } class Cat extends Animal { //构造方法 public Cat(String name,int age) { super(name,age); } //新添加的子类方法 public void sleep() { System.out.println(this.name + "正在睡觉......"); } }
我们尝试用上述过程来调用以下子类的中的方法:
public static void main(String[] args) { Animal animal = new Cat("橘猫",2); animal.eat(); animal.sleep(); }
但是等我们写好了后,就会发现编译器报错了
也就是说:
使用向上转型后,我们可以正常调用父类中的成员方法,但是不能调用子类中自己的方法
但是要解决上述问题还是很简单的,当我们在子类中重写父类方法后,我们就可以调用子类方法了,这也就是我们多态的实现
class Animal { String name; int age; //构造方法 public Animal(String name,int age) { this.name = name; this.age = age; } public void eat() { System.out.println(this.name + "正在吃食物~~~"); } public void sleep() { } } class Cat extends Animal { //构造方法 public Cat(String name,int age) { super(name,age); } public void sleep() { System.out.println(this.name + "正在睡觉......"); } }
public static void main(String[] args) { Animal animal = new Cat("橘猫",2); animal.eat(); animal.sleep(); }
现在我们就可以正常调用输出了:
总结:
当我们通过向上转型新建了一个对象后,我们可以通过这个对象来访问父类中的方法,但是不能访问子类中自己的方法,除非我们在子类中重写父类方法,也就是说当一个方法只有在父类和子类中都出现的情况下,我们才能访问子类中的这个方法
通过向上转型新建的对象可以访问的方法范围是:
- 父类有 子类没有
- 父类有 子类也有
不能访问的范围是:
- 父类没有 子类也没有
- 父类没有 但子类有
通过传参
class Animal { String name; int age; //构造方法 public Animal(String name,int age) { this.name = name; this.age = age; } public void eat() { System.out.println(this.name + "正在吃食物~~~"); } } class Dog extends Animal { //构造方法 public Dog(String name,int age) { super(name,age); } public void eat(){ System.out.println(this.name + "正在吃狗粮~~~"); } } class Cat extends Animal { //构造方法 public Cat(String name,int age) { super(name,age); } public void eat(){ System.out.println(this.name + "正在吃猫粮~~~"); } }
public static void fun(Animal animal) { animal.eat(); }
fun(new Dog("哈士奇",2)); fun(new Cat("橘猫",2));
我们通过一个方法来接受一个父类对象,然后通过这个父类对象来调用eat方法,当我们传入的参数是一个子类对象的时候,就相当于我们用父类对象做参数来接到了子类对象,也就是发生了向上转型
输出结果:
通过返回值
class Animal { String name; int age; //构造方法 public Animal(String name,int age) { this.name = name; this.age = age; } public void eat() { System.out.println(this.name + "正在吃食物~~~"); } } class Dog extends Animal { //构造方法 public Dog(String name,int age) { super(name,age); } public void eat(){ System.out.println(this.name + "正在吃狗粮~~~"); } } class Cat extends Animal { //构造方法 public Cat(String name,int age) { super(name,age); } public void eat(){ System.out.println(this.name + "正在吃猫粮~~~"); } }
public static Animal fun1(Animal animal) { return new Cat("布偶",3); } public static Animal fun2(Animal animal) { return new Dog("哈士奇",2); }
我们用父类对象做返回值类型,但是我们返回的是子类对象,这也就相当于发生了向上转型
向上转型的优点:让代码实现更简单灵活。
向上转型的缺陷:不能调用到子类特有的方法
二.向下转型
将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换
class Animal { String name; int age; //构造方法 public Animal(String name,int age) { this.name = name; this.age = age; } public void eat() { System.out.println(this.name + "正在吃食物~~~"); } public void sleep() { } } class Cat extends Animal { //构造方法 public Cat(String name,int age) { super(name,age); } public void sleep() { System.out.println(this.name + "正在睡觉......"); } } public class Test_4 { public static void main(String[] args) { Animal animal = new Cat("橘猫",2); Cat cat = new Cat("布偶",2); animal.eat(); animal.sleep(); cat = (Cat)animal; cat.eat(); cat.sleep(); } }
输出结果:
instanceof
向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换
public static void main(String[] args) { Cat cat = new Cat("元宝",2); Dog dog = new Dog("小七", 1); // 向上转型 Animal animal = cat; animal.eat(); animal = dog; animal.eat(); if(animal instanceof Cat) { cat = (Cat)animal; } if(animal instanceof Dog) { dog = (Dog)animal; } }
对于instanceof的详细信息可以查看官方资料:
Chapter 15. Expressions (oracle.com)