设为首页收藏本站

新微赢技术网

 找回密码
 注册
搜索
热搜: 回贴
查看: 5279|回复: 1
打印 上一主题 下一主题

JAVA中的异常和反射

[复制链接]
跳转到指定楼层
1#
发表于 2009-11-30 02:53:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
JAVA中的异常和反射
一、异常
1
、异常概貌:
概念: JAVA 会将所有的异常、错误抽象成为一个类,其根本父类为Throwable。异常是程
序中所有出乎意料的结果,用名称代表发生的问题,见名知义。我们对于程序可能出现的错
误应该做出预案。异常处理可以提高我们系统的容错性、健壮性。
java.lang.Throwable 类是所有异常和错误的顶层类。其两个直接子类是java.lang.Error 和
java.lang.Exception。
? Error
对象表示程序错误,是底层的、不可恢复的严重错误。此时程序一定会退出,
已经失去了运行所必须的物理环境。因为程序已经退出了,所以对于Error 错误无法进
行处理。
我们可处理的只是Exception
类的对象表示的程序异常(例外/异常)。
以下区分:
? RuntimeException
(未检查异常):RuntimeException 及其子类都称为运行时异常,它
是(UnChecked Exception),特点是Java 编译器不会检查它,可以在编程时避免。也就
是说,当程序中出现此类异常时,即使不用try…catch 捕获,或不用throws 子句抛出,
还是可以编译通过。比如,除数为0 的异常ArrithmeticException,就是运行时异常。
? 非Runtime
异常(已检查异常):包括除了RuntimeException及其子类外的其它Exception
类及其子类,都属于已检查异常(Checked Exception)。其特点是Java 编译器会检查它,
我们需要用try…catch 语句捕获,或用throws 子句声明抛出,否则编译不会通过。比如
打开文件时找不到文件,就属于已检查异常。
Throwable
Error
错误
严重底层错误
不可避免
不可处理
Exception
异常
RuntimeException
未检查异常
(可处理可不处理)
比如除0 错误、空指针
非Runtime
已检查异常
(必须处理)
比如打开文件时找不到

2
2
、Java
异常处理机制
(1
)try

catch
捕获异常(积极处理异常的方式)
try 代码块包含了可能发生异常的程序代码,catch 块紧随其后,用来捕获并处理异常。
格式如下:
try
{
可能出现异常的代码块}
catch
(Exception
e)
{
进行异常处理}
注意:一次异常捕获只会匹配一次try…catch
catch 中要求必须先捕获子类异常再捕获父类异常。
(2
)finally
任何情况下都必须执行的代码段(紧接在try 或catch 代码块后面)。
finally 无论如何都会被执行,除非JVM 退出。所以,finally 代码块常常用于释放被占
用的资源。比如关闭文件、网络、数据库连接等。
(3
)throws
声明可能会抛出的异常(消极处理异常的方式)
格式: 方法名(参数表)throws
后面接要往上抛的异常。
表示该方法对指定的异常不作任何处理,直接抛往上一层。
static void methodA(int i) throws IOException{ //一直向上抛(消极处理)
}
public static void main(String[] args) throws IOException{ //一直抛到JVM
}
多个异常,用逗号隔开。throws IOException, SQLException
throws 后的异常允许多态。比如IOException,会包括抛出其子类。
注意:不允许子类比父类抛出范围更大、更多的异常。
方法覆盖时,修饰符要越来越宽;抛例外则要越来越窄。
throws
和try

catch
经常配合使用,把异常传递给最能处理此异常的方法中,体现各
司其职的特点。
Java
中处理异常方式
消极throws 用在方法的声明上
积极try…catch…finally
public static int fn(int b){
try{
return b/2;
}catch(Exception e){
return 0;
}finally{
return b; //返回的结果是一定是b;
}
}

3
(4
)throw
抛出异常
打个比方:
public void eat() throws FoodException{ //自定义FoodException 是以下异常的父类
if(没有食物) throw new NoFoodException(“呵呵,没有食物”);
if(发现苍蝇) throw new FoundFlyException(“哎呀,发现半只苍蝇”);
}
比较throw
和throws

? throw
是一个语句,它出现在方法体中,用来抛出异常对象。
? throws
是出现在方法声明中,表示本方法中会有异常对象向上(调用者)抛出。
? throws
后写的是异常类型; throw
后写的是要抛出的异常对象。
(5
)异常处理流程
try…catch…finally,如果遇到return 和System.exit()语句:
㈠如果在finally 之前遇到System.exit()则finally 语句不再执行,这是finally 不被执行
的唯一情况。因为java.lang.System类的静态方法exit()用于终止当前的Java 虚拟机进程。exit()
的参数表示程序终止时的状态码,0 表示正常终止,非0 表示异常终止。
㈡return 语句用于退出本方法。如果在try 或者catch 代码块中遇到return 语句时,若
有finally 语句块,会先执行finally 代码块。
㈢不要在finally 代码块中使用return 语句。因为这样会导致两种潜在错误:A. 覆盖了
try 或catch 块中的return 语句; B. 导致丢失异常。
try{



} catch(XxxException e) {

} finally {

}

情况一:没有异常,处理顺序为① ② ③ ⑤ ⑥
情况二:在②处有异常,① ② ④ ⑤ ⑥
情况三:有异常,没有被捕获,① ② ⑤ ?终止
情况四:如果③后有return 语句,① ② ③ ⑤
情况五:如果遇到System.exit(),则⑤不执行
允许的处理方式:
① try…catch()
② try…finally //与throws 配合使用
③ try…catch…finally
④ try…catch(){} catch(){} … //配多个catch
//注意范围大的异常要写在后面

4
(6
)异常处理规则:
① 只有在异常情况下才使用异常处理机制;
② 保证操作要么一起成功,要么一起失败;
③ try 代码块不要太大;
④ catch 子句中指定具体的异常类型;
⑤ 早抛出,晚捕获。
3
、Java
异常类
Throwable 类提供了访问异常信息的一些方法,主要有两个:
e.getMethod()
—— 返回String 类型的异常信息。
e.printStackTree()
—— 打印跟踪方法调用栈获得的详细异常信息。主要是便于程序的调试
异常栈:
方法调用的关系: 看以下异常信息,通过层层追踪,发现问题。
Exception in thread "main" java.lang.RuntimeException: 找不到报表
at day09.exception.Employee.getReport(Employee.java:9)
at day09.exception.Manager.getReport(Manager.java:14)
at day09.exception.CFO.getReport(CFO.java:14)
at day09.exception.CEO.getReport(CEO.java:16)
at day09.exception.Test.main(Test.java:9)
4
、自定义异常
自定义异常要是Exception 类或其子类,以下是一个例子:
class MyException extends Exception{ //自定义的异常,这里是Exception 的子类
public MyException(String message){
//注意在构造父类对象时需要String 类型的message 作为参数
super(message); //传给父类,让父类设置
}
}
建议:我们一般会在项目中建立异常树结构,定制总异常和各种子异常。
小结一下,异常部分的着重掌握点:
1、异常类型的划分、区别;
2、异常处理的代码,各种不同情况下代码的执行顺序;
3、异常栈的概念(异常抛出的原理)
4、throw 和throws 的作用;
5、自定义异常类型。
异常栈信息
这里是从
主线程中
抛出的

5
二、反射
动态操作Java 代码,并解释分析类能力的程序,被称为反射。
反射的用途:广泛运用于开发工具、框架等。比如开发Hibernate、依赖注入等就是利
用反射技术来生成一套代码。所以,反射最大特点是针对通用编程,避免了硬编码。
java.lang.Class 用来描述某种数据类型。包括类、接口、数组、基本数据类型,都属于
数据类型,专门用Class 类来描述各自的数据类型。
1. 类对象通过类加载
Class 类对象(封装类的信息)
例如Student.class Teacher.class 在虚拟机中
编译后.class 文件为类的信息在JVM 中的体现:
关于类加载:类的加载是指把类的.class 文件中的二进制数据读到内存中,把它存放在运
行时的方法区中,然后在堆区创建一个java.lang.Class 对象,用来封装类在方法区内的数据
结构。
例如,动物园每类动物都有一个介绍牌子,介绍的是该类的信息。
牌子是一个描述该类信息的对象,即动物类的类对象。
区分概念:(以下类比帮助我们理解)
类?? 企鹅类
对象?? 类的对象,就是一只企鹅
类对象?? 牌子,牌子类的对象
Class
类?? 牌子类
如何获得一个类的类对象?有如下三种方法:
(1) Class c1=String.class; //类名加.class 前提为知道类名
(2) Student s1=new Student(“XiaoQiang”); //通过类的对象得到类对象
Class c2=s1.getClass(); //得到Student 所属类的类对象
getClass()是Object 中的方法,是不允许覆盖的。
例子: String s1=”123”;
String s2=”456”;
Class c1=s1.getClass();
Class c2=s2.getClass(); c1==c2 的判断结果为true. 全类只有一个类对象
JVM
Studen
t
Teacher
6
最常见也最灵活的方式:
(3) String className=”java.lang.String”; //用字符串当参数
Class c3=Class.forName(className); //静态方法。会发生类加载
有可能此类未被加载,则要先加载(通过类名找到文件加载),再返回类对象
注意:① 类名应写为——全限定名。即包名+类名
② class.forName()会导致类加载。类加载只装载一次,且类对象全类只有一个。
③ 类名.class 也会导致类加载。与forName 的差别: forName 是把类名当作参数,
代码中可不出现,更灵活;它们的返回结果都是一样的。
forName()的使用场合:类名以字符串形式存在时。并且可以在运行中改变。另外,
className 必须是类名或者接口名,否则forName()会抛出已检查异常,所以要做好异常处理。
2.Java 类反射中的主要方法详查课堂例子,或查看API。
对于以下三类组件中的任何一类来说– 属性、构造方法和方法-- java.lang.Class 提供
四种独立的反射调用,以不同的方式来获得信息。调用都遵循一种标准格式。
以下是用于查找构造方法的一组反射调用:
Constructor getConstructor(Class... parameterTypes) 获得使用特殊的参数类型的公
共构造方法
Constructor[] getConstructors() -- 获得类的所有公共构造方法
Constructor getDeclaredConstructor(Class... params) -- 获得使用特定参数类型的构
造方法
Constructor[] getDeclaredConstructors() -- 获得类的所有构造方法
用于获得方法信息的方法:
Method getMethod(String name, Class... params) -- 使用特定的参数类型,获得命名的
公共方法
Method[] getMethods() -- 获得类的所有公共方法
Method getDeclaredMethod(String name, Class... params) -- 使用特定的参数类型,获
得类声明的命名的方法
Method[] getDeclaredMethods() -- 获得类声明的所有方法
7
3.反射更大的功能: 通过类对象,得到类的对象。借此能操纵这个类。
对类对象调用newInstance() 则用无参构造方法构造一个其对象
Object o1=new Student(); //直接生成
? 等价于
Class c1=Class.forName(“Student”);
Object o2=c1.newInstance();
通过类对象获得类的对象?? “通过企鹅的牌子得到一只小企鹅”
Student s2=new Student(“XiaoMing”); ?
s2.study(“CoreJava”); 等价于
? 等价于
反射编程一般步骤:
Step1: 通过类名获得类对象
Class c=Class.forName(
“Student”)
;
Step2: 获得我们想要的构造方法对象Constructor Object
Class[] paramenters={ String.class }; // 返回Class[] 数组
Constructor con=c.getConstructor
(paramenters); //类对象数组作为参数
Step3: 调用构造方法,创建对象
Object[] os={“XiaoMing”};
Object o=con.newInstance
(os);
Step4: 获得想要调用的方法对象用getMethod( 方法名,Class[] )
Method m=c.getMethod
(“study”, parameters);
Step5: 对创建好的对象调用指定的方法
Object[] os2={“CoreJava”};
m.invoke
(o, os2); //针对o 对象调用m 方法,传入的是os2 参数;返回的
是Object 类型,null 表示返回为void.
注,两种写法的对应关系: 最大特点,把固有的信息参数化了,实现了通用编程。
反射生成
Constructor con=c.getConstructor(String.class);
Object o2=con.newInstance(“XiaoMing”);
Mithod m=c.getMethod(“study”, String.class);
m.invoke(o2, “CoreJava”); //表示调用o2 对象的study 方法, 以CoreJava 为参数
类名
方法参数
String str = (String)m.invoke(obj2, “CoreJava”); //反射写法
String str = obj2.study(“CoreJava”); //平时写法
8
小结一下,反射部分的着重掌握点:
1、Class 类;
2、得到Class 对象的三种方法;
3、Class、Package、Method、Modifier、Fileld、Constructor 这些类的常用方法;
4、用反射生成对象、调用方法、访问属性;
5、通过课堂例子理解反射使用与框架的意义。
三、常用集合类继承关系总览:
说明:以上是类图,表示类、接口之间的继承或者实现关系。其中圆圈代表接口,方框代表
类(有三栏,分别是类名、属性、方法——属性和方法这里省略了),实线空心箭头(指向
父类)代表继承关系,实线加圆圈代表实现一个接口。虚线加箭头表示依赖。那么,什么是
依赖呢?如果你的引用在我这里是个局部变量,就是说“我用你”,这就是依赖。比如
Collection 接口继承了Iterable 接口,Iterable 接口中有一个属性就是Iterator。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

申请友链|小黑屋|最新主题|手机版|新微赢技术网 ( 苏ICP备08020429号 )  

GMT+8, 2024-11-18 22:56 , Processed in 0.123585 second(s), 9 queries , Gzip On, Memcache On.

Powered by xuexi

© 2001-2013 HaiAn.Com.Cn Inc. 寰耽

快速回复 返回顶部 返回列表