常见加载类错误分析
在执行 Java程序时经常会碰到ClassNotFoundException和NoClassDefFoundError两个异常,它们都和类加载有关,下面详细分一下这两个异常的原因。
ClassNotFoundException
ClassNotFoundException恐怕时Java程序员经常碰到的异常,尤其是初学者来说,简直是让人崩溃,明明那个类就在那里,为啥就是找不到呢?无数个Java程序员都是这样问过自己。 这个异常通常发生在显式加载类的时候,例如用如下方式调用加载一个类时就报这个错了。
public class NotfoundException {
public static void main(String[] args) {
try {
Class.forName("NotfoundException");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
显式加载通常由如下方式:
- 通过类Class中的forName()方法
- 通过类ClassLoader中的loadclass()方法
- 通过类ClassLoader中的findSystemClass()方法 出现这类错误也很好理解,就是当JVM要加载指定文件的字节码到内存时,并没由找到这个类对应的字节码,也就是说这个字节码.class文件不存在。解决方法就是检测在当前的classpath目录下有没有指定的文件存在,如果不知道classpath路径,就可以通过如下命令获取:
this.getClass().getClassLoader().getResource("").toString()
NoClassDefFoundError
NoClassDefFoundError是另一个经常遇到的异常,这个异常在第一次使用命令执行Java类时很可能会碰到,如下面这种情况
java -cp example.jar Examper
在这个jar包里面只有一个类,这个类时net.xx.Exmple ,可能让你感到郁闷的是,命名这个jar包里面有这个类为啥会报这个错呢? 这是因为你在命令行中没有加类的包名,正确的写法是这样的
java cp example.jar net.xx.Example
在JVM的规范中描述了出现NoClassDefFoundError可能的情况就是使用new关键字、属性引用某个类、继承了某个接口或者类,以及方法的某个参数中引用了某个类,这个是出发JVM隐式加载这些类时发现这些类不存在的异常。
解决这个错误的方法就是确保这个类引用的类都在当前的classpath下面
UnsatisfiedLinkError
这个异常倒不是很常见,但是出错的话,通常是在JVM启动的时候,如果一不小心将在JVM的某个lib删除了,可能就会报这个错误了,代码如下
package test;
public class NolibException {
public native void nativeMethod();
static {
System.loadLibrary("Nolib");
}
public static void main(String[] args) {
new NolibException().nativeMethod();
}
}
这个错误通常时在解析native标识的方法时JVM找不到对应的本机库文件时出现,代码如下
java.lang.UnsatisfiedLinkError: no Nolib in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at test.NolibException.<clinit>(NolibException.java:6)
Exception in thread "main"
Process finished with exit code 1
ClassCastException
这个错误也很常见,通常在程序中出现强制类型转换时出现这个错误,如下面:
package test;
import java.util.HashMap;
import java.util.Map;
public class CastException {
public static Map map = new HashMap(){{
put("a","2");
}};
public static void main(String[] args) {
Integer integer = (Integer) map.get("a");
System.out.println(integer);
}
}
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at test.CastException.main(CastException.java:12)
JVM在做类型转换时会按照如下规则进行检查
- 对于普通对象,对象必须时目标类的实例或目标类的子类的实例。如果目标是是接口,那么会把它当作实现了接口的一个子类。
- 对于数组类型,目标类必须是数组类型或java.lang.Object、java.lang.Cloneable、java.io.Serializele 如果不满足上面的规则,JVM就会报这个错误。要避免这个错误有两种方式:
- 在容器类型中现实的指明这个容器所包含的对象类型,如在上面的map中可以写为
public static Map<String,Integer> map = new HashMap<String, Integer>(){{
put("a",2);
}};
,这样运行就可以没问题。 - 先通过instanceof检查是不是目标类型,然后再进行强制类型转换。
ExceptionInInitializerError
这个错误在JVM规范中是这样定义的:
- 如果Java 虚拟机试图创建类ExceptionInInitializerError的新实例,但是因为出现Out-Of-Memory-Error而无法创建新实例,那么就抛出OutOfMemoryError对象作为代替。
- 如果初始化器抛出一些Excepton,而且Exception类不是Error或者它的某个子类,那么就会创建ExceptioinInInitializerError类的一个新实例,并用Exception作为参数,用这个实例代替Excepiton。
将上面的代码例子稍微改一下:
package test;
import java.util.HashMap;
import java.util.Map;
public class CastException {
public static Map<String,Integer> map = new HashMap<String, Integer>(){{
map.put("a",2);
}};
public static void main(String[] args) {
Integer integer = (Integer) map.get("a");
System.out.println(integer);
}
}
这段代码在执行时报错如下:
java.lang.ExceptionInInitializerError
在初始化这个类时,给静态属性map赋值时出现了异常导致抛出错误ExceptionInInitializerError
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SurfaceView播放视频发送弹幕并实现滚动歌词
- RecyclerView实现流式标签单选多选功能
- Android中AlertDialog四种对话框的最科学编写用法(实例代码)
- Android判断手机是否联网及自动跳转功能(收藏版)
- 使用Flutter实现一个走马灯布局的示例代码
- Android按钮美化样式的实现代码
- android自定义组件实现仪表计数盘
- Android10填坑适配指南(实际经验代码)
- Android中外接键盘的检测的实现
- Android Q适配之IMEI替换为Android_id
- Android实现折线走势图
- Android Selector 按下修改背景和文本颜色的实现代码
- Android使用RecyclerView实现投票系统
- Android Selector获取焦点后文本背景修改的实现代码
- 基于SceneForm实现子弹射击(绘制子弹运行轨迹)