您的位置:首页 > 编程语言 > Java开发

Java基础之内部类、匿名类和异常处理知识点总结

2014-12-02 20:29 706 查看
 Object是java中已有的一个所有类的父类。也称为根类,你可以把它理解为java中的上帝。java中的类都是直接或者间接继承自object类。
该类的出现:是封装了所有对象都具备的方法。
所有对象都具备方法有哪些呢?
boolean  equals(Object obj):对对象进行比较。该方法的默认是比较内存地址,所以很多对象都对该方法进行复写。建立对象的自己比较是否相同的方式。
StringtoString():将对象变成字符串:格式: 对象类型@对象哈希值,但是这个结果没什么意义,所以,该方法一般也会被覆盖,建立该对象的自己特有的对应字符串的表现形式。
inthashCode():获取每一个对象的哈希值,可以理解为是地址值,是通过哈希算法完成的。
ClassgetClass():获取一个对象的所属字节码文件对象。
void finalize():垃圾回收器调用的垃圾回收方法。释放资源和释放内存。


例子1:Object类具备的方法实例演示。

package cn.itheima.day15;
class Demo {
/**
* Demo类本身是Object类的子类,具备了对象的比较相同的功能:equals(),因为是继承
* 过来的,而equals()方法是对地址值进行比较的,所以没什么意义。
* 所以想要建立Demo类自己的独特的比较方式。
* 既然父类中已经有了比较的功能,所以,子类只要继承该功能,并复写该功能即可。
*/
private int num;
public Demo(int num) {
this.num = num;
}
/**
* 建立Demo类的对象的比较方式,只要覆盖equals()方法接口。
* 沿袭父类的功能声明即可,定义子类的功能具体的实现。
* 一般情况下,描述对象,都会对该方法复写,建立该对象特有的比较是否相同的功能。
*/
//复写equals()方法
public boolean equals(Object obj){
if(this==obj)  //提高效率
return true;
if(!(obj instanceof Demo))   //增加健壮性
return false;
Demo d = (Demo)obj; //向下转型,是为了使用子类的特有功能。
if(this.num == d.num){
return true;
}
return false;
}
//复写toString()方法
public String toString(){
return "Demo's num="+num;
}
}
class Person{
}
public class ObjectDemo {
public static void main(String[] args) {
Demo d1 = new Demo(5);
Demo d2 = new Demo(7);
Demo d3 = new Demo(5);
System.out.println(d1);
System.out.println(d2);
System.out.println(d3);
System.out.println(d1.hashCode());
//任何一个对象都需要加载其对应的字节码文件来完成。
//也就说任何一个对象都有自己对应的字节码文件。
//如何获取该字节码文件呢?
//是通过Object 类中的getClass方法来完成。
Class clazz = d1.getClass();
//getClass方法返回的是d1这个对象所对应的字节码文件对象。Demo.class文件对象。
System.out.println(clazz.getName());

Person p = new Person();
System.out.println(p.getClass().getName());
System.out.println(d1.equals(d2));
System.out.println(d1.equals(d3));
//通过打印结论:equals()方法其实实在对对象的地址值进行判断
//判断两个对象是否是同一个地址。
/*Demo d1 = new Demo(5);
Demo d2 = new Demo(7);
Demo d3 = new Demo(5);
boolean b = d1.equals(d2);
boolean b1 = d1.equals(d3);
System.out.println("b="+b);
System.out.println("b1="+b1);
System.out.println(d1==d2);
System.out.println(d1==d3);*/
}
}

例子2:垃圾回收器finalize()方法的实例演示。

package cn.itheima.day15;
class Demo1{
public void finalize(){   //至少做了两件事:释放关联底层资源,释放内存空间
System.out.println("finalize run");
}
}
/**
* 被垃圾回收器是在不定时的时间启动。
* 现在准备手动调用垃圾回收器。
* @author wl-pc
*/
public class FinalizeDemo {
public static void main(String[] args) throws InterruptedException {
new Demo1();
new Demo1();
new Demo1();
Thread.sleep(10);
System.gc();  //启动垃圾回收器
}
}

内部类:又叫内置类或者嵌套类。将类定义在另一个类中,该类就是内部类。类中定义的类就是内部类。其实类的定义位置发生了一点小变化。
访问方式:
     内部类可以直接访问外部类中的成员。
     外部类想要访问内部类,需要建立内部类对象。

例子1:定义一个内部类的应用实例。

package cn.itheima.day15;
class Outer{
private int num = 3;
class Inner{  //定义的内部类
void show(){
System.out.println("inner show run--"+num);
}
}
public void method(){
Inner in = new Inner();
in.show();
}
}
public class InnerClassDemo {
public static void main(String[] args) {
Outer out = new Outer();
out.method();
}
}
/**
*  class Body{
private class Heart{
}
public Heart getHeart(){
if(...); //具有可控制性
return new Heart();
}
}
class Main{
Body body = new Body();
Body.getHeart();
}
*/

有A类和B类,当A类想要直接访问B类中的成员,而B类又需要建立A类的对象,来访问A类中的成员。这时,就将A类定义成B类的内部类。比喻:孙悟空和铁扇公主。孙悟空到了公主肚子中,就成了内部类。
class B{
   class A{}
}
什么时候定义内部类呢?
当分析一个事物时,该事物的内部还有具体的事物,这个具体的事物在使用该事物中的其他成员。这时就将这个具体的事物用内部类来描述。
比如:人体是一个类,人体有心脏,心脏的功能在直接访问人体的其他内容。这时就将心脏定义在人体类中,作为内部类存在。
而且内部类通常都不会直接对外提供,都会封装到外部类中,外部了一般会通过对外提供方法的形式对其进行访问内部类只有默认权限修饰符,或者 public修饰符时,可以被外部类直接访问到。
Outer.Innerin = new Outer().new Inner();
注意要保证的是该内部类必须定义在外部类的成员位置上。
格式:外部类名.内部类名 变量 = 外部类对象.内部类对象;
但是一般不会这么用,因为内部类都会被外部类隐藏,通常都是外部类提供方法获取内部类的对象。这样可以对获取对象可控。通常内部类都会被private私有化。
    Outer.Inner in = new Outer().new Inner();
    in.show();
当内部类中如果有静态成员时,该内部类也必须是静态的。而静态内部类只能访问外部类中的静态成员。    
在执行static内部类方法时,两种情况。
1,内部类静态,但是方法没静态。该方法需要被对象调用执行。
          Outer.Inner in = new Outer.Inner();//产生了一个静态内部类对象。
          in.show();
2,内部类静态,而且方法也是静态的。静态内部类随着对象的加载就已经存在了,静态方法随着内部类的加载也存在了。这时是不需要对象的。
Outer.Inner.show();

例子2:内部类中的静态和非静态的方法以及变量访问方式。

package cn.itheima.day15;
class Outer2{
private int num = 4;
static int num2 = 8;  //只要内部类定义在成员位置上,就可以被成员修饰符所修饰。
static class Inner{   //静态内部类只能访问外部类中的静态成员。
static void show(){
System.out.println("show run::"+num2);
}
}
/*public void method(){
Inner in = new Inner();
in.show();
}*/
}
public class InnerClassDemo2 {
public static void main(String[] args) {
/*Outer2 out = new Outer2();
out.method();*/
/*Outer2.Inner out= new Outer2().new Inner();
out.show();*/
//Outer2.Inner in = new Outer2.Inner(); //产生了一个静态内部类对象。
//in.show();
Outer2.Inner.show();
}
}

非静态的内部类之所以可以直接访问外部类中的成员,那是因为内部类中都持有一个外部类对象引用:外部类名.this
静态的内部类之所以可以直接访问外部类中的静态成员,其实持有的是外部类名。记住只有内部类定义在成员位置上,才可以有这些成员修饰符。


例子3:定义在成员位置上的内部类的修饰符用法实例演示。

package cn.itheima.day15;
class Outer3{
int num = 4;
static int num2 =9;
class Inner{
int num = 8;
void show(){
int num = 3;
System.out.println("show run::"+num);   //打印3
System.out.println("show run::"+this.num);   //打印8(用this是调用内部类自身的成员变量)
System.out.println("show run::"+Outer3.this.num);  //打印4(用类名.this是在调用外部类中的成员变量)
}
}
static class Inner2{
static void function(){
System.out.println("show run::"+num2);  //打印9 这时省略了Outer3.num2
}
}
public static void method2(){
Inner2 in2 = new Inner2();
in2.function();
}
public void method(){
Inner in = new Inner();
in.show();
}
}
public class InnerClassDemo3 {
public static void main(String[] args) {
Outer3 out = new Outer3();
//out.method();
out.method2();
}
}

内部类定义在类中的局部位置。内部类定义局部位置上,只能访问该局部中的被final修饰的常量。

例子4:内部类定义在类中的局部位置上。
package cn.itheima.day15;
/**
* 内部类定义在类中的局部位置上。
* 内部类定义局部位置上,只能访问该局部中的被final修饰的常量。
* @author wl-pc
*/
class Outer4{
int num = 4;
public void method(){
final int num2 = 8;  //定义常量
class Inner{
void show(){
System.out.println("show run::"+num2);
}
}
new Inner().show();
}
}
public class InnerClassDemo4 {
public static void main(String[] args) {
new Outer4().method();
}
}

匿名内部类:就没有名字的内部类。
    好处:简化了内部类的书写。
    前提:内部类必须要继承或者实现一个外部类或外部接口
匿名内部类的格式:
    new 父类名或者接口(){
里面定义该父类或者接口的子类成员。
}
匿名内部类其实就是一个子类匿名对象。这是一个带有内容的对象,这个对象有点胖。

例子5:匿名内部类的实例演示。

package cn.itheima.day15;
/**
* 匿名内部类
* @author wl-pc
*/
abstract class AbsDemo{
abstract void show();
}
class Outer5{
private int num = 4;
/*	class Inner extends AbsDemo{
void show(){
System.out.println("num="+num);
}
}*/
//匿名内部类的格式
public void method(){
new AbsDemo() {   //匿名内部类其实就是一个子类匿名对象
@Override
void show() {
System.out.println("num==="+num);
}
}.show();
}
}
public class NiMingInnerDemo {
public static void main(String[] args) {
new Outer5().method();
}
}

例子6:匿名对象的面试题。

package cn.itheima.day15;
//定义一个接口
interface Inter{
void show1();
void show2();
}
class Outer6{
/*class Inner implements Inter{
@Override
public void show1() {
System.out.println("show1 run");
}
@Override
public void show2() {
System.out.println("show2 run");
}*/
public void method(){
Inter in = new Inter(){
public void show1(){
System.out.println("show1 run");
}
public void show2(){
System.out.println("show2 run");
}
};
in.show1();
in.show2();
}
}
class Demo2{
void function(){
System.out.println("demo funtion run");
}
}
public class NiMingInnerDemo2 {
public static void main(String[] args) {
//new Outer6().method();
//new Demo2().function();  //创建Demo类的对象,调用function方法。
//需求:想要使用Demo类子类复写function后的该方法。
new Demo2(){   //创建了一个Demo类的子类匿名对象
void function(){
System.out.println("heima");
}
}.function();
}
//面试题:
/*new Object(){
void method(){
System.out.println("method run");
}
}.method();//问?可不可以运行? 可以的。
*/
//问下面的情况可不可以?
Object obj = new Object(){
void method(){
System.out.println("method run");
}
};
//obj.method();  //会编译失败
//原因解释:
/**
* 分析:等号右边的部分是一个Object类的子类对象,
* 用匿名内部类来表示的。当把这个对象赋值给Object类型
* 的obj时,该子类对象就是向上转型为了Object。obj中是
* 没有定义过method方法。这就是我们说在多态时,一般非静态
* 函数被调用时,编译看左边(Object中有没有method()方法呢?
* 没有,则编译失败),运行看右边的原理。
* (举例:猫是动物,会抓老鼠,所以动物都会抓老鼠)错误想法。
*/
/*
class Test extends Object{
void method(){}
}
new Test().method();
Object obj = new Test();
obj.method();//编译失败
*/
}

什么时候使用匿名内部类呢?
当函数的参数是一个接口类型的引用,而且该接口中的方法不超过3个。这时可以给这个函数传递一个匿名内部类实际参数进入。简化书写。

例子7:匿名内部类的实例演示。

package cn.itheima.day15;
interface Inter2{
void show();
}
class Outer7{
//补足代码,要求用匿名内部类来体现。
static Inter2 method(){
return new Inter2(){  //返回接口的子类对象
public void show(){
System.out.println("show run");
}
};
}
}
public class NiMingTest {
public static void main(String[] args) {
//Inter in = Outer.method();
//in.show();
//Outer7.method().show();// Outer7.method():说明Outer7类中有一个method方法。
//这个方法时直接被Outer7所访问,代表这个方法时静态的。
//Outer7.method()方法运行完,还可以调用show()方法,说明method运行结束后,会返回一个
//show方法所属接口Inter2的子类对象。而且method方法返回值类型肯定是Inter2.
//举例说明:当函数的参数是一个接口类型的引用,而且该接口中的方法不超过3个。
//这时可以给这个函数传递一个匿名内部类实际参数进入
function(new Inter2(){
public void show(){
System.out.println("inner show run");
}
});
}
public static void function(Inter2 in){  //可以给这个函数(function)传递一个匿名内部类实际参数进入.
in.show();
}
}

异常:就是程序运行时出现的不正常情况。

例子8:异常的演示代码。

package cn.itheima.day15;
class Demo4{
public int div(int a,int b){
return a/b;
}
public void method(){
int[] arr = new int[3];
System.out.println(arr[3]);
}
}
public class ExceptionDemo {
public static void main(String[] args) {
Demo4 d = new Demo4();
/*int num = d.div(4, 0);  //除0异常
System.out.println("num="+num);
System.out.println("over");*/
d.method();   //角标越界异常ArrayIndexOutOfBoundsException
System.out.println("over");
}
}

发现,当调用者往里传入了除数0,就发生。编译通过(语法没错误),而运行失败的情况。出现一个ArithmeticException:/ by zero 一个异常。运行提前终止,后续的代码就不会在执行了。
其实异常就是程序中出现的问题:这个问题包括:问题的名称,问题的信息,以及问题出现的位置。这个问题中内部中的有很多,按照面向对象将这个问题封装成了对象。
通过if判断形式,也可以对问题进行处理。但是这样会导致,问题处理代码和正常的业务流程代码都定义在了一起,不便于阅读,当把问题封装成对象后,当该问题产生后,可以让程序进行跳转有一个特定的区域对问题进行处理。
这样,异常的出现可以是问题处理代码和业务逻辑代码相分离,提高了程序的阅读性。Java对常见的一系列都进行了描述,并进行了对象的封装。
查阅一下API。发现异常中很多子类。
因为常见问题很多,就对这些问题进行描述并建立了体系。
异常问题分为两大类:
    1,可以处理的问题。
一般用Exception(异常)来进行描述。这个问题可以有针对性的代码进行处理。
    2,重大错误问题,
用Error进行描述。这个问题发生后,一般不编写针对的代码进行处理,而是要对程序进行修正。
通常都有JVM抛出的问题。
    这两个派系,他们的子类都有一个共同特征:所有子类名成结尾都是以父类名作为后缀。
问题:就如同疾病:可以治愈的疾病。Exception也有绝症。Error.无论错误还是异常,他们都有:名称标识,同时也有问题的信息、问题出现的位置。
既然有这样的共性可以向上继续抽取。它们都有了一个共同的父类Throwable,该父类中就定义了该体系中最共性的方法.
String getMessage():获取异常的信息。
String toString():将异常对象变成字符串。其实该类是覆盖Object类中的toString();
void printStackTrace():打印异常在内存中的详细信息。直接打印到控制台。
异常的处理。有两种:
1,将异常抛出。
2,使用java中指定的代码块进行自定义处理。
try{
               需要检测异常的代码;
}
catch(异常类 变量){
               异常处理代码;
}
finally{
              一定会被执行的代码;
}

例子9:异常处理的实例演示。

package cn.itheima.day15;
class Demo5{
public int div(int a,int b){
return a/b;
}
}
public class ExceptionDemo2 {
public static void main(String[] args) {
Demo5 d = new Demo5();
try {
int num = d.div(4, 0);  //除0异常
System.out.println("num="+num);
} catch (Exception e) {   //定义一个异常类的引用,用于接收发生的异常。
System.out.println("有异常存在!");
System.out.println("message:"+e.getMessage());  //只返回异常信息
System.out.println("toStrig:"+e.toString());//既有异常信息,又有异常类名称
e.printStackTrace(); //异常名称,异常信息,异常出现的位置。都打印在控制台上。
//发现没有进行trycatch处理时,由jvm默认处理的结果和printStackTrace的结果一致。
//说明jvm的默认处理方式,就是在调用异常的printStackTrace方法。并让程序停止。
}
System.out.println("over");
}
}

处理异常:
要么throws(抛出异常),要么try…cacth。到底是try…cacth好呢?还是throws好呢?
 原则:如果该功能内部可以将问题处理,用try…cacth,如果处理不了,交由调用者处理,这时用throws。
例子10:try…cacth和throws(抛出异常)实例演示。

package cn.itheima.day15;
/**
* 调用了div功能,该功能并未声明有任何问题,所以调用者是不需要进行针对处理。
*   但是这样程序会有安全隐患。
*   所以在定义div功能时,就需要将容易发生的问题,明确出来,这样才方便于调用者进行处理.
* 怎么明确呢?
*   可以在功能上通过throws关键字将问题的名称标识出来,让调用者可以知道.
* @author wl-pc
*/
class Demo6{
public int div(int a,int b) throws Exception{
return a/b;
}
}
public class ExceptionDemo3 { //throws Exception //抛出异常(主函数就抛给了虚拟机JVM)
public static void main(String[] args) {
Demo6 d = new Demo6();
try {
int num = d.div(4, 0);  //除0异常
System.out.println("num="+num);
} catch (Exception e) {
System.out.println("发生异常!");
}
System.out.println("over");
}
}

如果使用到了一个声明了异常的功能时,必须要对应的抛出throws或者try的处理方式。否则编译失败。但是有一种特殊情况。当功能上声明的异常是一个特殊的异常子类时,这时该功能被调用,可以不用任何处理方式,一样可以编译通过。这个特殊异常就是Exception中的一个子类RuntimeException。(运行时异常)
异常分两种:
1,编译时被检测的异常.包括除了Exception子类RuntimeException以外的所有异常。如果在函数上声明,如果调用时,没有处理方式,编译会编译。而且这种异常需要有针对性的处理方式。是可被处理的。
2,编译时不被检测的异常:包括RuntimeException以及子类。
    该异常也称为运行时异常,如果功能声明了此异常,调用者可以不用任何处理方式。通过该异常不需声明。如果发生,就是需要程序停止,对代码进行修正。

例子11:运行时异常的实例演示。

package cn.itheima.day15;
class Demo7 {
public int div(int a,int b) throws RuntimeException{
return a/b;
}
}
public class ExceptionDemo4 {
public static void main(String[] args) {
Demo7 d = new Demo7();
int num = d.div(4, 0);  //除0异常
System.out.println("num="+num);
System.out.println("over");
}
}

在自定义项目中,也会有很多问题发生,这些问题,有可能是项目特有问题,是没有被java所描述的。那么这时,就需要我们继续按照java的异常思想,将特有问题也封装成对象。自定义异常。将特有的问题进行描述,并封装成对象。
//在下面示例中,要求,除数不可以为负数。
这种问题java没有提供先有的描述方式。所以只有自己进行描述。
自定义异常的步骤:
    定义一个类对问题描述。要想成为异常,必须继承异常类才可以。这样才可以成为异常体系中的一员。其实最根本原因:异常体系和其他对象的不同之处在于异常体系都具备可抛性。
    异常的类和对象都可以被两个关键字所操作,而且只有异常体系具备这个特点,哪两个关键字呢?throws和throw
当函数内容通过throw抛出了一个编译时检测的异常。必须要有处理方式。要么try,要么throws。
处理调用出现异常的函数的原则:
调用了声明异常的函数,处理时,对方声明什么异常,我们就处理什么异常。自定义异常可以继承Exception,也可以继承RuntimeException。如果该问题发生,不需要声明需要是调用修正代码,那么就需要继承RuntimeException。

throws和throw的区别:
throws用在函数上,用于声明该功能容易出现问题。可以调用者进行处理的。
throw用在函数内,用于抛出指定的具体异常对象。
throws后面跟的是异常类。可以跟多个,中间用逗号隔开。
throw后面跟的是异常对象。
只有异常体系的类和对象才可以被这两个关键字所操作。
例子12.自定义异常类的实例演示。

package cn.itheima.day15;
class FuShuException extends RuntimeException{ //Exception{
private int num;
public FuShuException(String msg,int num) {
super(msg);
this.num = num;
}
public int getNum(){
return num;
}
}
class Demo8 {
public int div(int a,int b) {//throws FuShuException{
//如果标示throws FuShuException,则主函数会去执行的,
//而往往我们是希望出现异常,是不往下执行的,所以不要标示出
if(b<0)
//手动将异常封装成对象,并手动通过throw关键字将异常抛出,引起程序跳转
//因为程序发生异常后,运算是无法继续运行的。
throw new FuShuException("除数不能为负数", b);
return a/b;
}
}
public class ExceptionDemo5 {
public static void main(String[] args) {
Demo8 d = new Demo8();
//try {
int num = d.div(4, -1);
System.out.println("num="+num);
//} catch (FuShuException e) {
//System.out.println("负数产生!");
//System.out.println(e.getMessage());
//System.out.println(e.toString());
//System.out.println("负数是:"+e.getNum());
//}
System.out.println("over");
}
}
//分析FuShuException怎样自定义一个异常的类
/*class Throwable{
private String message;
public Throwable(String message) {
this.message = message;
}
public String getMessage(){
return message;
}
}
class Exception extends Throwable{
public Exception(String message) {
super(message);
}
}
class FuShuException extends Exception{
FuShuException(String message){
super(message);
}
}*/

例子13.异常的处理的实例演示。

package cn.itheima.day15;
/**
* 老师用电脑上课。
* 在老师上课的时候容易出现的问题:
*    1.电脑蓝屏
*    2.电脑冒烟
* @author wl-pc
*  分析事物是,要考虑容易出现的问题,当然我们应该尽量的避免问题的出现
*  ,但是如果避免不了,应该预先的给出处理方式。
*  需要将分析出来的问题进行描述,并将其封装成对象,
*/
//电脑蓝屏异常
class LanPingException extends Exception{
public LanPingException(String msg) {
super(msg);
}
}
//电脑冒烟异常
class MaoYanException extends Exception{
public MaoYanException(String msg) {
super(msg);
}
}
//当电脑发生问题后,会导致老师讲课的进度无法继续的问题出现
class NoPalanException extends Exception{  //讲课的进度无法继续异常
public NoPalanException(String msg) {
super(msg);
}
}
//定义电脑的实例对象
class computer{  //try异常后是不需要在声明抛出异常的,但是如果要不处理异常,那就得声明抛出的异常
int state = 2;
void run() throws LanPingException, MaoYanException{
if(state == 1){
throw new LanPingException("电脑蓝屏!");
}
if(state == 2){
throw new MaoYanException("电脑冒烟!");
}
System.out.println("电脑运行!");
}
void reset(){
state = 0;
System.out.println("电脑重启!");
}
}
//定义老师实例
class Teacher{
private String name;
private computer cmp;
public Teacher(String name) {
this.name = name;
cmp = new computer();
}
//上课
void preflect() throws NoPalanException {
try {
cmp.run();
System.out.println(name+"开始上课!");
} catch (LanPingException e) {
System.out.println("蓝屏!");
cmp.reset();
preflect();
} catch (MaoYanException e1){
System.out.println(e1.getMessage());
test();
//new dnweixiou().weixiou(cmp);
throw new NoPalanException("课程无法继续"+e1.getMessage()); //异常转换:将异常封装,暴露出调用可以解决的异常。
}
}
void test(){
System.out.println("大家做练习!");
}
}
/*class dnweixiou{
void weixiou(computer cmp){
cmp.reset();
}
}*/
public class ExceptionTest {
public static void main(String[] args) throws MaoYanException {
Teacher t = new Teacher("毕老师");
try {
t.preflect();
} catch (NoPalanException e) {
System.out.println(e.getMessage());
}
}
}
/*
* 举例说明:异常的封装,将本层的特定的异常进行本层的处理。
* 通过处理完对外暴露,将问题高数调用者,给调用者提供一个
* 可以处理的异常。这就是异常转换。
* class SQLperate{
*      void add() throw new SQLException{
*           拦截数据库。
*           添加数据。 //这时会抛出异常throw new SQLException
*           关闭数据库。
*        }catch(SQLException e){
*           //解决数据库异常的代码。
*           throw new NoAddException();
*        }
*      }
* }
* //向数据库中没添加成功的异常
* class NoAddException extends Exception{
*     ......
* }
* class Demo{
*    main(){
*        try{
*           new SQLperate().add();
*        }catch(NoAddException e){
*           throw new NoAddException("添加数据失败");
*        }
*    }
* }
* */

finally代码块。finally代码块中定义是用于关闭资源的代码。
举例:
操作数据库。无论数据是否添加成功,都需要进行数据库的关闭动作,因为关闭动作可以释放数据库的资源。提高数据库的性能。
void add(){
    try{
       连接数据库。
       添加数据。
    }
    catch(SQLExceptione){
       异常处理方式。
    }
    finally{
       关闭数据库
    }
}
Try…catch…finally在使用的时候,try可以和catch相结合使用,可以对应多个catch。如果没有catch,try可以和finally结合使用。
如果功能中,出现了编译时“需要被检测的异常”字样时,如果没有被catch,就必须要throws声明,否则编译失败
记住:只有catch是处理异常的代码块.
void show()throws Excpetion{
    try{
       code();//使用了底层资源。
       thrownew Excpetion();
    }  
    finally{
       资源释放。
    }
}

例子14. Finally用法的实例演示。

package cn.itheima.day15;
class Demo9{
public int div(int a,int b) throws Exception{
return a/b;
}
}
public class ExceptionDemo6 {
public static void main(String[] args) {
Demo9 d = new Demo9();
try {
int num = d.div(4, 0);  //除0异常
System.out.println("num="+num);
} catch (Exception e) {
System.out.println(e.toString());
//return;
System.exit(0); //退出javajvm。
}finally{  //只有一种情况finally执行不到。退出jvm。
System.out.println("finally run");
}
System.out.println("over");
}
}

异常的处理细节:
1,当子类覆盖父类时,如果父类的方法抛出了异常,那么子类覆盖父类要么不抛异常,要么抛出该异常或者该异常的子类。
2,如果父类抛出了多个异常,子类覆盖父类时,只能抛出这些异常子集。
简单一句话:子类只能抛父类的异常或者异常的子类或子集。子类不可以抛出父类没有的异常

例子15.异常处理的细节实例。
package cn.itheima.day15;
/**
* Exception
* |--AException
* |--BException
* |--CException
* @author wl-pc
*/
class AException extends Exception{
}
class BException extends AException{
}
class CException extends Exception{
}
class Fu{
void show() throws AException{
System.out.println("Fu");
}
}
class Tool{
void method(Fu f){
try {
f.show();
} catch (AException e) {
e.printStackTrace();
}
}
}
class Zi extends Fu{
void show() throws AException{ //还可以抛出BException,但是不可以抛出CException
System.out.println("Zi");
}
}
public class ExceptionDemo7 {
public static void main(String[] args) {
Tool tool = new Tool();
tool.method(new Zi());
}
}

注意:如果被覆盖的方法没有异常抛出,那么子类的方法绝对不可以抛出异常。如果子类方法内还有异常发生。那么子类只能try,不能throws.
面试细节:当try对应多个catch时,如果catch的类型有继承关系,那么父类型的catch一定要放在下面.

/*
* class Fu{
void show()throws AException,CException,Exception{
}
}
try {
new Fu().show();
}
catch(AException e){
}
catch(CException e){
}
catch(Exception e){
}
* */
*/
void method()
{
if()
throw new RuntimeException();
System.out.println("haha");//永远执行不到。是一句标准的废话。
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息