通常情况下,我们在创建对象的时候,声明对象名称的数据类型与创建对象的数据类型是一致的,例如:A a=new A();
这里的A代表一个类型,但有些时候我们用一个父类声明对象名称,而用子类去创建对象,即用一个父类引用一个子类类型的对象,例如:
A a=new B();//A为父类,B为子类 或者 A a;//a引用上转型对象 B b=new B(); a=b;
上转型对象:
是一种“特殊类型(功能受限制)
”的子类对象,它强调父类的特性而忽略子类的特性。
举例:
package anmial; //anmial为父类 public class Animal { public void show(){//父类方法 System.out.println("I am a dog"); } }
import anmial.Animal; //Pig为子类 public class Pig extends Animal { @Override public void show() {//重写父类方法 System.out.println("I am a Pig"); } public void shows(){//子类特有的方法 System.out.println("我每天除了吃就是睡"); } }
import anmial.Animal; public class test { public static void main(String[]args){ Animal animal=new Pig();//这里的animal为上转型引用对象 animal.show(); } }
输出:
从父类继承的方法中被改写的部分,成功输出。
下面我们再尝试调用一下,子类特有的属性。
animal.shows();
结果报错:
由此我们可以得出上转型对象具有以下特性:
<1>上转型对象只能访问从父类继承而来的属性,方法以及实例化对象时的类中定义的覆盖方法(上转型对象只能访问A中被继承的属性,方法以及B中定义的覆盖方法)。
<2>上转型对象不能访问实例化对象时所增加的成员属性和方法(上转型对象不能访问B类[子类]新增的属性和方法)。
那子类特有的属性就没有办法被调用了吗?
那当然不是!
针对于这种情况,那种情况呢?
由于上转型对象无法访问子类新增的成员属性和方法,所以在某些情况下需要将上转型对象转换成子类对象,才能访问子类新增的成员属性和方法,其实下转型对象就是一个普通的子类对象。
转换格式:
(要转换的子类数据类型)上转型对象;
还是上述实例:
import anmial.Animal; public class test { public static void main(String[]args){ Animal animal=new Pig(); animal.show(); ((Pig)animal).shows();//将上转型对象转换为子类对象 } }
输出:
子类特有方法被成功调用。
//这里的Pig为子类对象,animal为上转型对象 ((Pig)animal).shows();//将上转型对象转换为子类对象
注意:
<1>只有针对上转型对象才能进行下转操作,非上转型对象不能进行下转操作。
<2>使用上转型对象机制的优点是体现了面对对象的多态性,增强了程序的简洁性。
在对象下转的操作过程中,需要明确知道转换的数据类型,如果下转的类型不明确或者不当,进行下转操作时,会引发ClassCastException异常。
为了避免出现异常,确保下转操作执行正确,在下转操作前需要对上转型对象进行类型判断,此时需要使用instanceof关键字。
语法格式如下:
//用来判断左边的对象引用是否属于右边的类型==左边的对象是否属于右边类型的实例 对象名 instanceof 对象所属类型
在我们上述实例中:
//上转型引用对象animal是否属于Pig if(animal instanceof Pig)
注意:
<1>在上转型对象进行下转操作前,为了避免出现异常,一定要使用instanceof进行对象类型判断。
<2>上转型对象的本质其实还是一个子类对象,只不过是一个“限制版”的子类对象,子类对象新增的成员属性和方法不能使用而已。
<3>Aniamal类的call方法可以设计成重载的形式,如下例所示:这样通过用Animal的子类类型作为实参,这样call方法就不用进行下转型操作,传递过来的就是一个实际的子类 对象,可以调用子类特有的方法。
package TEST; public class Aninmal { public void run(){ System.out.println("Animal中的run方法"); } public void eat(){ System.out.println("Animal中的eat方法"); } public void sleep(){ System.out.println("Animal中的sleep方法"); } public void move(){ System.out.println("Animal中的move方法"); } //将实际的子类传递过来 public static void call(Sheep sheep){//将call方法设置成重载方式 sheep.special(); sheep.move(); sheep.eat(); sheep.sleep(); } public static void call(dog dog){//将call方法设置成重载方式 dog.special(); dog.move(); dog.eat(); dog.sleep(); } } //dog类 class dog extends Aninmal{ String name="小狗"; @Override public void eat(){ System.out.println(name+"在吃东西"); } @Override public void sleep(){ System.out.println(name+"在睡觉"); } @Override public void move(){ System.out.println(name+"在移动"); } public void special(){ System.out.println("这是"+name+"特有的方法"); } } //Sheep类 class Sheep extends Aninmal{ String name="绵羊"; @Override public void sleep(){ System.out.println(name+"在睡觉"); } @Override public void eat(){ System.out.println(name+"在吃东西"); } @Override public void move(){ System.out.println(name+"在移动"); } public void special(){ System.out.println("这是"+name+"特有的方法"); } } //测试类 class Text { public static void main(String[]args){ Aninmal sheep1=new Sheep(); Aninmal dog1=new dog(); Aninmal.call((Sheep) sheep1); Aninmal.call((dog) dog1); } }
输出
这是绵羊特有的方法 绵羊在移动 绵羊在吃东西 绵羊在睡觉 这是小狗特有的方法 小狗在移动 小狗在吃东西 小狗在睡觉