java.lang.ClassCastException剖析全(转)

java.lang.ClassCastException

 

java.lang.ClassCastException
当前者的域小于后者的时候出现
譬如说:前者A是子类的 对象,而后者B是父类的 对象
coding时,若使用A = B;就会抛出java.lang.ClassCastException
要说 类型 转换,首先要说一说java的数据 类型。java中的数据类型分为两种:基本类型、 引用类型。基本数据类型没有什么好说的byte char short int long float double boolean,这些类型除了boolean之外,其他的与C语言中的类型没有太大的区别。因为这篇文章的论题是类型 转换,所以在此不讨论boolean值的用法。
  下面要说的是引用类型。引用在有的书里也叫做句柄,它很类似C/C++中的指针,但要注意引用和指针并不是同 一个概念。指针是 一个存放地址的变量,他使C/C++程序员能够灵活地访问内存,但这也给程序的 安全 性带来了很大的隐患,由于程序员可以对指针随意的运算操作,所以一不留神就会破坏其他的存储单位,导致程序中出现意想不到的结果。引用继承了指针节省内存的优点,又限制了对地址的操作,所以他是安全的。引用类型包括所有类生成的实例和数组(不管是对象数组还是基本类型数组都实现Cloneable接口,所以他也是一个对象实例),所有引用类型都继承自Object这个类。要说明一点的是java中的所有变量都是一个引用,不管是引用类型还是基本类型。
  现在要正式讨论类型的转换了。用过C/C++的人对基本类型的转换都会很清楚,基本类型转换分为类型提升和强制转换。
  例如:
int a=100;
long b=a+100;//这个地方就用到了类型提升,a+100从int提升到了long
a=(int)b;//这个地方用到了强制转换
  强制类型转换在某种情况下会丢失精度,如:
byte b;
int a=200;
b=(byte)a;//虽然这里用到了强制转换,但因为byte的范围是-127到127
//所以强制转换后宽度会被截短
  在java中除了这些转换之外基本数据类型还可以被隐式的转换成String,例如:
System.out.print("转换"+100);//如果在数据前面有字符串用+连接
//就会隐式的转换成String
  引用类型的转换实现起来要比C++简单的多,如果一个对象与另一个对象没有任何的继承关系,那么他们就不能进行类型转换。如果要把一个派生类对象赋值给基类对象这个称为上溯造型。如果要把基类对象赋值给派生类对象就需要强制类型转换,这称为下溯造型,下溯造型有一些危险,要安全的进行下溯造型有一个前题,基类对象必须是从派生类对象中上溯过来的。
  例如:
class Base{}
class Child extends Base{
public static void main(String[] args){
Base base=new Child();//上溯造型
Child child=(Child)base;//下溯造型
Child child1=(Child)new
Base();//抛出ClassCastException异常
}
}
  最后,谈一谈String与引用类型的转换。前面已经说过,所有的对象都是从Object继承过来的,Object中有一个toString方法。这个方法是所有的对象都可以转换成String,如果想把自定义的类转换成String,最安全的做法是重写toString方法。和基本类型一样如果对象前有String对象用+连接,对象就会隐式转换成String,这种情况实际上是隐式调用了toString方法。



 

ClassCastException JVM 在检测到两个类型间转换不兼容时引发的运行时异常。此类错误通常会终止用户请求。在执行任何子系统的应用程序代码时都有可能发生 ClassCastException 异常。通过转换,可以指示 Java 编译器将给定类型的变量作为另一种变量来处理。对基础类型和用户定义类型都可以转换。 Java 语言规范定义了允许的转换,其中大多数可在编译时进行验证。不过,某些转换还需要运行时验证。如果在此运行时验证过程中检测到不兼容, JVM 就会引发 ClassCastException 异常。例如:
Fruit f;
Apple a = (Apple)f;
当出现下列情况时,就会引发 ClassCastException 异常:
1.        Fruit Apple 类不兼容。当应用程序代码尝试将某一对象转换为某一子类时,如果该对象并非该子类的实例, JVM就会抛出该异常
2.        Fruit Apple 类兼容,但加载时使用了不同的 ClassLoader 。这是这种异常发生最常见的原因。在这里,需要了解一下什么是 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 连接到线程的上下文。
基于以上的基本原理,可以加深大家对 ClassCastException 的理解,和在碰到问题时提供一种解决问题的思路。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值