简单使用
声明一个父类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)
解释:
- 正确的向下转型
Fruit a=new Apple(); //向上转型
a.myName();
Apple aa=(Apple)a; //向下转型,编译和运行皆不会出错(正确的)
aa.myName();//向下转型时调用的是子类的
a指向子类的对象,所以子类的实例aa也可以指向a
向下转型后因为都是指向子类对象,所以调用的当然全是子类的方法
- 错误的向下转型
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();
}