通常情况下,我们在创建对象的时候,声明对象名称的数据类型与创建对象的数据类型是一致的,例如: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);
}
}
输出
这是绵羊特有的方法
绵羊在移动
绵羊在吃东西
绵羊在睡觉
这是小狗特有的方法
小狗在移动
小狗在吃东西
小狗在睡觉