java向上转型和向下转型

转型是在继承的基础上而言的,继承是面向对象语言中,代码复用的一种机制,通过继承,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。

向上转型:通俗地说就是是将子类对象转为父类对象。此处父类对象可以是接口。(父类的引用指向子类对象,多态)

转型需要注意的问题:向上转型时,父类指向子类引用对象会遗失除与父类对象共有的其他方法,也就是在转型过程中,子类的新有的方法都会遗失掉,在编译时,系统会提供找不到方法的错误。实例如下:

public class Animal {
    public void eat(){
        System.out.println("Animal eating ...");
    }
}

public class Bird extends Animal{
    @Override
    public void eat(){
        System.out.println("Bird eating ...");
    }
    public void fly(){
        System.out.println("Bird flying ...");
    }
    public static void main(String[] args) {
        Animal animal = new Bird();
        animal.eat();
        //animal.fly();
        //The method fly() is undefined for the type of Animal
    }
}

向上转型:父类引用的对象转换为子类类型称为向下转型。这种情况分为两种类型:
1、如果父类引用的对象是子类对象,那么在向下转型的过程中是安全的。

Animal animal = new Bird();
Bird bird =(Bird)animal;

2、如果父类引用的对象是不是子类对象,那么在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现java.lang.ClassCastException错误。它可以使用instanceof来判断父类引用是否是指向子类对象。

Animal animal = new Animal();
Bird bird = (Bird) animal;
bird.eat();//java.lang.ClassCastException(不安全的向下转型,编译无错但会运行会出错)

Animal animal = new Animal();
//animal并不是一个指向Bird实例的引用,所以不会进入if中,向下转型,所以运行时不会引发ClassCastException错误
if(animal instanceof Bird){
    Bird bird = (Bird) animal;
    bird.eat();
}

一个比喻:说鸟是动物,向上转型,符合逻辑,不需要强转;反过来,说动物是鸟,向下转型,不符合逻辑,需要强转。(如果动物这个称谓引用指向的是鸟,则是成功的,反之失败)

java.lang.ClassCastException异常是一种RunTimeException异常,是unchecked型的(编译器不要求处置的异常)异常,所以上面会在编译时不报错,运行时会报错。

ClassCastException是JVM在检测到两个类型间转换不兼容时引发的运行时异常。通过转换,可以指示Java编译器将给定类型的变量作为另一种变量来处理。对基础类型和用户定义类型都可以转换,如果在此运行时验证过程中检测到不兼容,JVM就会引发ClassCastException异常。例如:

Animal animal = new Animal();
Bird bird = (Bird) animal;
bird.eat();//java.lang.ClassCastException(不安全的向下转型,编译无错但会运行会出错)

当出现下列情况时,就会引发ClassCastException异常:

1、两个类不兼容。向下转型失败,当应用程序代码尝试将某一对象转换为某一子类时,如果该对象并非该子类的实例,JVM就会抛出ClassCastException异常;

2、两个类兼容,但加载时使用了不同的ClassLoader。这是这种异常发生最常见的原因。

ClassLoader

ClassLoader是允许JVM查找和加载类的一种Java类。JVM有内置的ClassLoader。不过,应用程序可以定义自定义的ClassLoader。应用程序定义新的ClassLoader通常出于以下两种原因:

  1. 自定义和扩展JVM加载类的方式。例如,增加对新的类库(网络、加密文件等)的支持。

  2. 划分JVM名称空间,避免名称冲突。例如,可以利用划分技术同时运行同一应用程序的多个版本(基于空间的划分)。此项技术在应用服务器(如WebLogic Server)内的另一个重要用途是启用应用程序热重新部署,即在不重新启动JVM的情况下启动应用程序的新版本(基于时间的划分)。

ClassLoader按层级方式进行组织。除系统BootClassLoader外,其它ClassLoader都必须有父ClassLoader。

在理解类加载的时候,需要注意以下几点:

  1. 永远无法在同一ClassLoader中重新加载类。“热重新部署”需要使用新的ClassLoader。每个类对其ClassLoader的引用都是不可变的:this.getClass().getClassLoader()。

  2. 在加载类之前,ClassLoader始终会先询问其父ClassLoader(双亲委托模型)。这意味着将永远无法重写“核心”类。

  3. 同级ClassLoader间互不了解。

  4. 由不同ClassLoader加载的同一类文件也会被视为不同的类,即便每个字节都完全相同。这是ClassCastException的一个典型原因。

  5. 可以使用Thread.setContextClassLoader(a)将ClassLoader连接到线程的上下文。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值