内部类与异常类.ppt
第5章 内部类与异常类,本章要点,内部类匿名类异常类,内部类,Java支持在一个类中声明另一个类,这样的类称作内部类,而包含内部类的类成为内部类的外嵌类。某种类型的农场饲养了一种特殊种类的牛,但不希望其他农场饲养这种特殊种类的牛,那么这种类型的农场就可以将创建这种特殊种牛的类作为自己的内部类。例有一个RedCowFarm(红牛农场)类,该类中有一个名字为RedCow(红牛)的内部类。,public class RedCowFarm static String farmName;RedCow cow;/内部类声明对象 RedCowFarm()RedCowFarm(String s)cow=new RedCow(150,112,5000);farmName=s;public void showCowMess()cow.speak();,class RedCow/内部类的声明 String cowName=红牛;int height,weight,price;RedCow(int h,int w,int p)height=h;weight=w;price=p;void speak()(偶是+cowName+,身高:+height+cm 体重:+weight+kg,生活在+farmName);/内部类结束,public class Example public static void main(String args)RedCowFarm farm=new RedCowFarm(红牛农场);farm.showCowMess();();/RedCowFarm.RedCow redCow=new RedCowFarm.RedCow(180,119,6000);/如果将内部类定义为static,那么就可以用外部类名直接访问内部类的构造方法。/redCow.speak();/如果将内部类定义为static,那么声明的内部类的对象也可以直接访问内部类的方法。,内部类举例,class Outerint outer_i=100;void test()/外部类的某个方法Inner in=new Inner();/声明内部类的对象in.display();/调用内部类中的方法class Innervoid display()System.out.println(“display:outer_i:”+outer_i);/内部类访问外部类中的成员变量class InnerClassDemopublic static void main(String args)Outer out=new Outer();out.test();,使用内部类的好处,当一个类中要用到另一个类的实例对象,而另一个类中的代码又要访问第一个类中的成员,将另一个类做成第一个类的内部类,程序代码要容易编写。,内部类和外嵌类之间的关系,外嵌类中的成员变量在内部类中有效,内部类中的方法可以调用外嵌类中的方法。外嵌类可以用内部类声明对象,作为外嵌类的成员。内部类仅供外嵌类使用,其他类不可以用某个类的内部类声明对象。内部类可以用static修饰。,匿名类,匿名内部类就是重写父类或接口的方法。匿名内部类是没有名字的,所以没办法获得其类型,而只能把它当作超类或接口类型来使用。,和子类有关的匿名类,Java允许直接使用一个类的子类的类体创建一个子类对象。创建子类对象时,除了使用父类的构造方法外还有类体,此类体被认为是一个子类去掉类声明后的类体,称作匿名类。假设Bank是类,那么下列代码就是用Bank的一个子类(匿名类)创建对象:new Bank()匿名类的类体;,abstract class OutputAlphabet/输出字符的抽象类 public abstract void output();,public class OutputEnglish extends OutputAlphabet/继承抽象类 public void output()/实现了抽象方法 for(char c=a;c=z;c+)System.out.printf(“%3c”,c);/输出小写英文字母,public class ShowBoard void showMess(OutputAlphabet show)/上转型对象 show.output();,public class Example public static void main(String args)ShowBoard board=new ShowBoard();board.showMess(new OutputEnglish();/向参数传递OutputAlphabet的子类对象 board.showMess(new OutputAlphabet()/向参数传递OutputAlphabet的匿名子类对象,实现父类方法 public void output()for(char c=;c=;c+)/输出希腊字母 System.out.printf(%3c,c););/在此结束方法调用,和接口有关的匿名类,假设Computable是一个接口,那么,Java允许直接用接口名和一个类体创建一个匿名对象,此类体被认为是实现了Computable接口的类去掉类声明后的类体,称作匿名类。下列代码就是用实现了Computable接口的类(匿名类)创建对象:new Computable()实现接口的匿名类的类体;下例演示了和接口有关的匿名类的用法,public class Example public static void main(String args)HelloMachine machine=new HelloMachine();machine.turnOn(new SpeakHello()public void speak()/实现接口中的方法 System.out.println(hello,you are welcome!););machine.turnOn(new SpeakHello()public void speak()/实现接口中的方法(你好,欢迎光临!););,class HelloMachine public void turnOn(SpeakHello hello)hello.speak();,interface SpeakHello void speak();,异常,异常就是程序在运行时出现的不正常情况;我们的写的程序不可能一帆风顺,若异常产生,却没进行正确的处理。则可能导致程序的中断,造成损失,所以我们在开发中要考虑到各种异常的发生,并对其作出正确的处理,确保程序的正常执行。,了解异常,一旦出现异常,程序会立即终止,public class TestExceptionpublic static void main(String args)int result=new Test().devide(3,0);System.out.println(the result is:+result);class Testpublic int devide(int x,int y)int result=x/y;return result;,异常体系,异常体系,异常的体系ThrowableError通常指JVM出现重大问题如:运行的类不存在或者内存溢出等。不需要编写针对代码对其处理,程序无法处理。Exception 在运行时运行出现的一些情况,可以通过try,catch,finally处理Exception 和 Error的子类名大都是以父类名作为后缀。Java在设计异常体系时,将容易出现的异常情况都封装成了对象。,异常的分类,异常分类:编译时被检查异常;-Checked异常在程序中必须使用try.catch处理;编译时不被检测的异常;-Runtime异常可以不使用try.catch处理,但一旦出现异常就将由JVM处理。,异常的分类之Runtime异常,RuntimeException(运行时异常)是指因设计或实现方式不当而导致的问题.说白了,就是程序员造成的,程序员小心谨慎是完全可以避免的异常.比如,事先判断对象是否为null就可以避免NullPointerException异常,事先检查除数不为0就可以避免ArithmeticException异常特点:这种异常Java编译器不会检查它,也就说程序中出现这类异常的时候,即使不处理也没有问题,但是一旦出现异常,程序将异常终止,若采用异常处理,则会被相应的程序执行处理.,异常的分类之Checked异常,除了RuntimeException以及子类,其他的Exception及其子类都是受检查异常,我们也可以称为非RuntimeException异常.特点:Java编译器会检查它,也就说程序中一旦出现这类异常,要么是用try-catch语句捕获,要么用throws语句声明抛出它,否则无法编译通过,也就是说这种异常,程序要求必须处理.,处理异常的5个关键字,异常处理的5个关键字try,catch,finally throw,throws捕获异常:先捕获小异常再捕获大异常。程序是调出来的,不是写出来的;多测试是程序员的必修课。,异常处理格式,try/可能出异常的代码 catch(异常类 对象)/处理该异常类型的语句finally/一定会执行的代码/catch块使用System.exit(1);除外,异常处理后,程序不会因为出现异常而退出,当try语句块出现异常,程序会自动跳到catch语句块去找匹配的异常类型,并执行异常处理语句,finally语句块是异常的统一出口。,public class TestExceptionpublic static void main(String args)tryint result=new Test().devide(3,0);System.out.println(the result is:+result);catch(Exception e)e.printStackTrace();System.out.println(“OK!End here!”);class Testpublic int devide(int x,int y)int result=x/y;return result;,异常处理,throws,在可能出现异常的方法上声明抛出可能出现异常的类型:声明的时候尽可能声明具体的异常,方便更好的处理.当前方法不知道如何处理这种异常,可将该异常交给上一级调用者来处理(非RuntimeException类型的异常)。方法一旦使用throws声明抛出方法内可能出现的异常类型,该方法就可以不再过问该异常了;一个方法调用另一个使用throws声明抛出的方法,自己要么try.catch,要么也throws;,public 返回值类型 方法名(参数列表.)throws 异常类A,异常类B.,throw,自行抛出一个异常对象,抛出异常类的对象;若throw抛出的是Runtime异常:程序可以显示使用try.catch来捕获并处理,也可以不管,直接交给方法调用者处理;若throw抛出Checked异常:要么放在try里自己处理,要么放在一个throws声明的方法里面,交给调用者处理。,public static void main(String args)try fn1(1);catch(Exception e)e.printStackTrace();fn2(2);public static void fn1(int a)throws Exceptionif(a 0)throw new Exception(fn1-a值不合法);public static void fn2(int a)if(a 0)throw new RuntimeException(a值不合法);,throws&throw,throws用于在方法上声明该方法不需要处理的异常类型。throw用于抛出具体异常类的对象。throws与throw的区别:thorws用在方法上,后面跟异常类名,可以是多个异常类。throw用在方法内,后面跟异常对象,只能是一个。,例 给出数据转换出现异常的情况下trycatch语句的用法,public class Example public static void main(String args)int n=0,m=0,t=1000;try m=Integer.parseInt(8888);n=Integer.parseInt(ab89);/发生异常,转向catch t=7777;/t没有机会被赋值 catch(Exception e)(发生异常:+e.getMessage();System.out.println(n=+n+,m=+m+,t=+t);try(故意抛出I/O异常!);throw new(我是故意的);/(这个输出语句肯定没有机会执行,所以必须注释掉,否则编译出错);e)(发生异常:+e.getMessage();,Throwable中的方法,String getMessage()获取异常信息,返回字符串。String toString()获取异常类名和异常信息,返回字符串。void printStackTrace()打印异常在堆栈中的跟踪信息;获取异常类名和异常信息,以及异常出现在程序中的位置。方便程序开发阶段的调试(一般要打开);JVM默认的异常处理机制;,多异常处理,声明异常时尽可能声明具体异常类型,方便更好的处理;方法声明几个异常就对应有几个catch块;若多个catch块中的异常出现继承关系,父类异常catch块放在最后;在catch语句块使用Exception类作为异常类型时:所有子类实例都可以使用父类接收(向上转型),即所有的异常对象都可以使用Exception接收;注:在java处理多异常时捕获小范围的异常必须放在大范围异常之前。,多异常处理格式,try/可能出异常的代码 catch(异常类A 对象)/处理异常类型A的语句catch(异常类B 对象)/处理异常类型B的语句.finally/一定会执行的代码/catch块使用System.exit(1);除外,异常处理后,程序不会因为出现异常而退出,当try语句块出现异常,程序会自动跳到catch语句块去找匹配的异常类型,并执行异常处理语句,finally语句块是异常的统一出口。,方法覆写-异常,子类方法中声明抛出的异常类型是父类方法声明抛出异常类型的子类或相同类;也就是说:子类方法不能抛出新的异常类型;子类方法可以同时声明抛出多个父类方法声明抛出异常类的子类;(RuntimeException例外);,class Super public void show()throws IOExceptionclass Sub extends Super public void show()throws FileNotFoundException,IOException,IllegalAccessException,方法覆写原则,子类中方法与父类方法有相同的返回值类型;子类声明返回的类型也可以是父类声明返回类型的子类;子类中方法与父类方法有相同的方法签名;子类中方法的访问权限不能小于父类方法的访问权限;子类方法不能抛出新的异常类型;子类方法可以同时声明抛出多个父类方法声明抛出异常类的子类;(RuntimeException例外);子类方法可以引发更少的异常,甚至可以不引发任何异常,方法覆写-异常,public class RadioPlayer public void startPlaying()throws SoundException/body of method public class StereoPlayer extends RadioPlayer public void startPlaying()/body of method,finally,异常的统一出口:不管try块程序是否异常,也不管哪个catch执行,finally块总会执行。try语句块或会执行的catch语句块使用了JVM系统退出语句例外;/System.exit(1);try块必须和 catch块或和finally同在,不能单独存在,二者必须出现一个。,自定义异常类,也可以扩展Exception类定义自己的异常类,然后规定哪些方法产生这样的异常。一个方法在声明时可以使用throws关键字声明要产生的若干个异常,并在该方法的方法体中具体给出产生异常的操作,即用相应的异常类创建对象,并使用throw关键字抛出该异常对象,导致该方法结束执行。,程序必须使用try-catch语句捕获能抛出异常的方法。,通常情况下,计算两个整数之和的方法不应当有任何异常发生,但是,对某些特殊应用程序,可能不允许同号的整数做求和运算,比如当一个整数代表收入,一个整数代表支出时,这两个整数就不能是同号。,例,Bank类中有一个income(int in,int out)方法,对象调用该方法时,必须向参数in传递正整数、向参数out传递负数,并且int+out必须大于等于0,否则该方法就抛出异常。因此,Bank类在声明income(int in,int out)方法时,使用throws关键字声明要产生的异常。程序运行效果如图。,public class Bank private int money;public void income(int in,int out)throws BankException if(in=0|in+out=0)throw new BankException(in,out);/方法抛出异常,导致方法结束 int netIncome=in+out;(本次计算出的纯收入是:%d元n,netIncome);money=money+netIncome;public int getMoney()return money;,public class BankException extends Exception String message;public BankException(int m,int n)message=入账资金+m+是负数或支出+n+是正数,不符合系统要求.;public String warnMess()return message;,2023/10/9,第 40 页,public class Example public static void main(String args)Bank bank=new Bank();try bank.income(200,-100);bank.income(300,-100);bank.income(400,-100);(银行目前有%d元n,bank.getMoney();bank.income(200,100);bank.income(99999,-100);catch(BankException e)(计算收益的过程出现如下问题:);System.out.println(e.warnMess();(银行目前有%d元n,bank.getMoney();,应用举例,带finally子语句的trycatch语句,语法格式如下:try catch(ExceptionSubClass e)finally其执行机制是在执行trycatch语句后,执行finally子语句,也就是说,无论在try部分是否发生过异常,finally子语句都会被执行。,模拟向货船上装载集装箱,如果货船超重,那么货船认为这是一个异常,将拒绝装载集装箱,但无论是否发生异常,货船都需要正点启航。运行效果如图,public class CargoBoat int realContent;/装载的重量 int maxContent;/最大装载量 public void setMaxContent(int c)maxContent=c;public void loading(int m)throws DangerException realContent+=m;if(realContentmaxContent)throw new DangerException();(目前装载了+realContent+吨货物);,public class DangerException extends Exception final String message=超重;public String warnMess()return message;,public class Example public static void main(String args)CargoBoat ship=new CargoBoat();ship.setMaxContent(1000);int m=600;try ship.loading(m);m=400;ship.loading(m);m=367;ship.loading(m);m=555;ship.loading(m);catch(DangerException e)System.out.println(e.warnMess();(无法装载重量是+m+吨的集装箱);finally(货船将正点启航);,“”,