向上转型和向下转型

简单使用

声明一个父类Father,子类Son继承Father

Father a = new Son()  // 父类引用、子类对象(向上转型)

Son b = (Son)a  //  向下转型,强制转换
// 父类引用转成子类引用

向上转型实例

public class Animal {
  
  public void eat(){
    System.out.println("animal eatting...");
  }
}
class Bird extends Animal{
  
  public void eat(){
    System.out.println("bird eatting...");
  }
  
  public void fly(){
    
    System.out.println("bird flying...");
  }
}
class Main{
  
  public static void main(String[] args) {
    
    Animal b=new Bird(); //向上转型
    b.eat(); // 调用的是子类eat()
    //! error: b.fly();
    //  b虽指向子类对象,但此时子类作为向上转型的代价丢失和父类不同的fly()方法------
    dosleep(new Male());
    dosleep(new Female());
  }
  
  public static void dosleep(Human h) {
    h.sleep();
  }
}
public class Human {
  public void sleep() {
    System.out.println("Human sleep..");
  }
}
class Male extends Human {
  @Override
  public void sleep() {
    System.out.println("Male sleep..");
  }
}
class Female extends Human {
  @Override
  public void sleep() {
    System.out.println("Female sleep..");
  }
}

这里就可以看出向上转型的好处和使用场景了

public static void dosleep(Human h) {
    h.sleep();
}

这里的参数类型是父类,传入的值是子类,这就完成了向上转型操作。然后会自动判断调用该子类的对应方法。试想,如果我们这么干

public static void dosleep(Male male) {
    male.sleep();
}

public static void dosleep(Female fe) {
    fe.sleep();
}

......

这是人,要换成水果,给你来个几百种,不写死才怪。
因此向上转型很好的简化了代码,也正是体现了java的抽象编程思想,使代码变得解耦。

向下转型实例

class Fruit
  {
    public void myName()
    {
        System.out.println("我是父类  水果...");
    }
}
 
class Apple extends Fruit
{ 
    @Override
    public void myName() 
    { 
        System.out.println("我是子类  苹果...");
    }
    public void myMore()
    {
        System.out.println("我是你的小呀小苹果~~~~~~");
    }
}
 
public class Sys{ 
    public static void main(String[] args) { 
        Fruit a=new Apple(); //向上转型
        a.myName();
        
        Apple aa=(Apple)a; //向下转型,编译和运行皆不会出错(正确的)
        aa.myName();//向下转型时调用的是子类的
        aa.myMore();;
          
        Fruit f=new Fruit();
        Apple aaa=(Apple)f; //-不安全的---向下转型,编译无错但会运行会出错
        aaa.myName();
        aaa.myMore(); 
    }

}

输出:

我是子类  苹果...
我是子类  苹果...
我是你的小呀小苹果~~~~~~
Exception in thread "main" java.lang.ClassCastException: com.sheepmu.Fruit cannot be cast to com.sheepmu.Apple
at com.sheepmu.Sys.main(Sys.java:30)

解释:

  1. 正确的向下转型
        Fruit a=new Apple(); //向上转型
        a.myName();
        
        Apple aa=(Apple)a; //向下转型,编译和运行皆不会出错(正确的)
        aa.myName();//向下转型时调用的是子类的

a指向子类的对象,所以子类的实例aa也可以指向a

向下转型后因为都是指向子类对象,所以调用的当然全是子类的方法

  1. 错误的向下转型
        Fruit f=new Fruit();
        Apple aaa=(Apple)f; //-不安全的---向下转型,编译无错但会运行会出错
        aaa.myName();
        aaa.myMore(); 

这里f指向父类对象,子类实例肯定不能指向f

3.Java为了解决不安全的向下转型问题,引入泛型的概念

4.为了安全的类型转换,最好先用 if(A instanceof B) 判断一下对象类型

例:

if (f instanceof Apple){
    Apple aaa=(Apple)f;
        aaa.myName();
        aaa.myMore(); 
}

参考文章:https://blog.csdn.net/sheepmu/article/details/38327205

posted @ 2019-11-06 17:20  Gyyyang  阅读(...)  评论(... 编辑 收藏