java的引用类型转换分为两种:
- 向上类型转换,是小类型到大类型的转换
- 向下类型转换,是大类型到小类型的转换
现存在一个Animal动物类,猫子类和狗子类继承于Animal父类;
1 public class Animal { 2 private String name; 3 4 public String getName() { 5 return name; 6 } 7 8 public void setName(String name) { 9 this.name = name; 10 } 11 12 public void eat() { 13 14 } 15 } 16 17 public class Cat extends Animal { 18 public void eatFish() { 19 System.out.println("猫吃鱼"); 20 } 21 } 22 23 public class Dog extends Animal { 24 public void eatBone() { 25 System.out.println("狗吃骨头"); 26 } 27 }
实例化一个cat对象,如下:
1 Cat cat1 = new Cat(); //使用子类引用实例化子类对象 2 3 Animal cat2 = cat1; 4 //此时为向上引用转换,小类型转换为大类型,并没有风险 5 6 //Cat cat3 = cat2; //报错 7 //由于cat2已经是Animal类的引用,所以此时为向下引用转换,即大类型转换为小类型,有数据溢出的风险 8 //虽然有风险,但也可以强制转换 9 Cat cat3 = (Cat)cat2; //强制转换成功 10 11 //Dog dog1 = cat2; //因为子类不同所以不能这样引用 12 //Dog dog1 = (Dog)cat2; //即使强制转换也不行
虽然向下引用转换会存在风险,但是可以利用java的instanceof关键字去解决这个问题。instanceof运算符用法:判断是一个实例对象是否属于一个类,是返回true,否则返回false。这样我们可以优化上面的代码避免强制转换类型时出现的问题:
1 /** 2 * instanceof运算符用法 3 * 运算符是双目运算符,左面的操作元是一个对象,右面是一个类.当 4 * 左面的对象是右面的类创建的对象时,该运算符运算的结果是true,否则是false 5 * 6 * 说明:(1)一个类的实例包括本身的实例,以及所有直接或间接子类的实例 7 * (2)instanceof左边操作元显式声明的类型与右边操作元必须是同种类或右边是左边父类的继承关系, 8 * (3)不同的继承关系下,编译出错 9 */ 10 if(cat2 instanceof Dog) { 11 Dog dog = (Dog)cat2; 12 }else { 13 System.out.println("并不能转换"); 14 }
但是当子类实例对象统一放进父类引用对象数组时,若要使用子类中的方法,必须先向下转换类型为子类引用,不然编译器会报错
1 Animal[] animals = { 2 new Cat(), 3 new Dog() 4 }; 5 6 7 //animals[1].eatFish(); //报错 8 if(animals[1] instanceof Cat) { 9 Cat cat = (Cat)animals[1]; 10 }