Java中向上转型和向下转型的问题

一、向上转型

通俗地讲即是将子类对象转为父类对象。此处父类对象可以是接口。

1、向上转型中的方法调用

实例

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 doEat(Animal h) {
    h.eat();
  }
  public static void main(String[] args) {
    
    Animal b=new Bird(); //向上转型
    b.eat(); 
    //! error: b.fly(); b虽指向子类对象,但此时丢失fly()方法
    Animail c1=new Animal();
    Bird c2=new Bird();
    doEat(c1);
    doEat(c2);//此处参数存在向上转型
  }
}

注意这里的向上转型:

Animal b=new Bird(); //向上转型
b.eat();

此处将调用子类的 eat() 方法。原因:b 实际指向的是 Bird 子类,故调用时会调用子类本身的方法。

需要注意的是向上转型时 b 会遗失除与父类对象共有的其他方法。 如本例中的 fly 方法不再为 b 所有。还有需要值得注意的是!当子类向上转型之后调用成员变量即实例变量是父类的,调用的成员方法是子类的!

2、向上转型的作用

看上面的代码:
public static void doEate(Animail h) { h.sleep(); }
这里以父类为参数,调有时用子类作为参数,就是利用了向上转型。这样使代码变得简洁。不然的话,如果 doEate 以子类对象为参数,则有多少个子类就需要写多少个函数。这也体现了 JAVA 的抽象编程思想。

二、向下转型。

与向上转型相反,即是把父类对象转为子类对象。

1、向下转型中的方法调用

实例

public class Animail {
    private String name="Animail";
    public void eat(){
        System.out.println(name+" eate");
    }
}

class Human extends Animail{
    private String name="Human";
    public void eat(){
        System.out.println(name+" eate");
    }
}

class Main {
    public static void main(String[] args) {
        Animail a1=new Human();//向上转型
        Animail a2=new Animail();
        Human b1=(Human)a1;// 向下转型,编译和运行皆不会出错
 //       Human c=(Human)a2;//不安全的向下转型,编译无错但会运行会出错
    }
}

Animail a1=new Human();//向上转型
Human b1=(Human)a1;// 向下转型,编译和运行皆不会出错

这里的向下转型是安全的。因为 a1 指向的是子类对象。


Animail a2=new Animail();
Human c=(Human)a2;//不安全的向下转型,编译无错但会运行会出错

运行出错:

Exception in thread "main" java.lang.ClassCastException: study. 转型实例.Animail cannot be cast to study.转型实例.Human at study.转型实例.Main.main(Main.java:8)

2、向下转型的作用

向上转型时 b会遗失除与父类对象共有的其他方法;可以用向下转型在重新转回,这个和向上转型的作用要结合理解。

三、当转型遇到重写和同名数据

看下面一个例子,你觉得它会输出什么?

public class A {
	   public int i=10;
	   void print(){
	       System.out.println("我是A中的函数");
	   }
	}
	class B extends A{
	   public int i=20;
	    void print(){
	        System.out.println("我是B中的函数,我重写了A中的同名函数");
	    }
	    void speak(){
	        System.out.println("向上转型时我会丢失");
	    }

	   public static void main(String[] args) {
	        B b=new B();
	        A a=b;//此处向上转型
	        b.print();  System.out.println(b.i);
	        b.speak();
	        a.print();  System.out.println(a.i);
	        //a.speak(); 报错
	       ((B) a).speak();//a在创建时虽然丢失了speak方法但是向下转型又找回了
	    }
	}

结果

我是B中的函数,我重写了A中的同名函数
20
向上转型时我会丢失
我是B中的函数,我重写了A中的同名函数
10
向上转型时我会丢失

我们发现同名数据是根据创建对象的对象类型而确定,而这个子类重写的函数涉及了多态,重写的函数不会因为向上转型而丢失

四、多态存在的三个必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象

所以不要弄混淆了,父类的方法在重写后会被子类覆盖,当需要在子类中调用父类的被重写方法时,要使用super关键字

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值