第8章内部类与异常.ppt
第8章 内部类与异常类,Java支持在一个类中声明另一个类,这样的类称作内部类,而包含内部类的类称为内部类的外嵌类。内部类的外嵌类的成员变量在内部类中仍然有效,内部类中的方法也可以调用外嵌类中的方法。内部类的类体中不可以声明类变量和类方法。外嵌类的类体中可以用内部类声明对象,作为外嵌类的成员。,8.1 内部类,内部类仅供它的外嵌类使用,其他类不可以用某个类的内部类声明对象。另外,由于内部类的外嵌类的成员变量在内部类中仍然有效,使得内部类和外嵌类的交互更加方便。,例8-1,public class RedCowForm String formName;RedCow cow;/内部类声明对象 RedCowForm()RedCowForm(String s)cow=new RedCow(150,112,5000);formName=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()System.out.println(偶是+cowName+,身高:+height+cm 体重:+weight+kg,生活在+formName);,public class Example8_1 public static void main(String args)RedCowForm form=new RedCowForm(红牛农场);form.showCowMess();,8.2.1 和子类有关的匿名类创建子类对象时,除了使用父类的构造方法外还有类体,此类体被认为是一个子类去掉类声明后的类体,称作匿名类。匿名类就是一个子类,由于无名可用,所以不可能用匿名类声明对象,但却可以直接用匿名类创建一个对象。,8.2 匿名类,匿名类例子,new Bank()匿名类类体;假设Bank是类,那么上面代码就是用Bank的一个子类(匿名)类创建的对象。,由于匿名类是一个子类,但没有类名,所以在用匿名类创建对象时,要直接使用父类的构造方法。尽管匿名类创建的对象没有经过类声明步骤,但匿名对象的引用可以传递给一个匹配的参数,匿名类的常用的方式是向方法的参数传值。,匿名类可以继承父类的方法也可以重写父类的方法。使用匿名类时,必然是在某个类中直接用匿名类创建对象,因此匿名类一定是内部类,匿名类可以访问外嵌类中的成员变量和方法,匿名类的类体中不可以声明static成员变量和static方法,例8-2,ShowBoard类的showMess(InputAlphabet show)方法的参数是InputAlphabet类型的对象,用户在编写程序时,希望使用ShowBoard类的对象调用showMess(InputAlphabet show)输出英文字母表和希腊字母表,但系统没有提供输出希腊字母表的子类,因此用户可以使用匿名类来实现,abstract class InputAlphabet public abstract void input();public class InputEnglish extends InputAlphabet public void input()for(char c=a;c=z;c+)System.out.printf(%3c,c);,public class ShowBoard void showMess(InputAlphabet show)show.input();public class Example8_2 public static void main(String args)ShowBoard board=new ShowBoard();board.showMess(new InputEnglish();/向参数传递InputAlphabet的子类对象 board.showMess(new InputAlphabet()/向参数传递InputAlphabet的匿名子类对象 public void input()for(char c=;c=;c+)/输出希腊字母 System.out.printf(%3c,c););,假设Computable是一个接口,那么,Java允许直接用接口名和一个类体创建一个匿名对象,此类体被认为是实现了Computable接口的类去掉类声明后的类体,称作匿名类。下列代码就是用实现了Computable接口的类(匿名类)创建对象:new Computable()实现接口的匿名类的类体;如果某个方法的参数是接口类型,那么可以使用接口名和类体组合创建一个匿名对象传递给方法的参数,类体必须要重写接口中的全部方法,8.2.2 和接口有关的匿名类,例8-3,interface SpeakHello void speak();class HelloMachine public void turnOn(SpeakHello hello)hello.speak();public class Example8_3 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()System.out.println(你好,欢迎光临!););,所谓异常就是程序运行时可能出现一些错误Java的异常出现在方法调用过程中,即在方法调用过程中抛出异常对象,终止当前方法的继续执行,同时导致程序运行出现异常,并等待处理,8.3 异常类,Java中常见异常,RuntimeException:一些特殊的异常,比如被0除,数组下标越界等,处理比较麻烦。而且对程序的可读性以及运行效率影响很大,因此由系统自动检测并将它们交给缺省的异常处理程序(用户可不必对其处理)ArithmeticException:数学计算异常ArrayStoreException:数组存储异常NegativeArraySizeException:负数组长度异常ArrayOutOfBoundsException:数组索引越界异常NullPointException:空指针异常IOException(用户必须对其处理!)FileNotFoundException:文件未找到异常EOFException:读写文件尾异常MalformedURLException:URL格式错误异常SocketException:Socket异常,Java中处理异常,Java处理异常是用5个关键字实现的try catch finally throw throws,捕获异常,catch,try,finally,执行可能产生 异常的代码,捕获异常,无论是否发生异常,代码总能执行,手动抛出异常,抛出异常,throw,声明异常,声明方法可能要抛出的各种异常,throws,异常处理方式,两种处理方式:(1)使用trycatchfinally结构对异常进行捕获和处理(2)通过throws和throw抛出异常,trycatchfinally结构,try/可能会抛出特定异常的代码段catch(异常类型1 引用1)/如果引用1 被抛出,则执行这段代码catch(异常类型2 引用2)/如果另外的异常引用2被抛出,则执行这段代码 finally/无条件执行的语句各个catch参数中的异常类都是Exception的某个子类,表明try部分可能发生的异常,这些子类之间不能有父子关系,否则保留一个含有父类参数的catch即可,说明,(1)try将可能出现异常的代码都放在try代码块中(2)catch-如果try内出现了异常,系统将终止try块代码的执行,自动跳转到所发生的异常类对应的catch块中。执行该块中代码(3)finally是可选项,无论异常是否发生,该块都执行。一般用来善后处理,说明,(4)catch与finally不能同时省略(5)try.catch以及finally语句块之间不能插入任何代码,例1:捕获数组下标越界异常,public class Exception1 public static void main(String args)try int a=1,2,3,4,5,sum=0;for(int i=0;i=5;i+)sum=sum+ai;System.out.println(sum=+sum);System.out.println(Successfully!);catch(ArrayIndexOutOfBoundsException e)System.out.println(ArrayIndexOutOfBoundsException detected);finally System.out.println(Programm Finished!);,例2:捕获算术异常,public class Exception2 public static void main(String args)try int x,y;x=15;y=0;System.out.println(x/y);System.out.println(Computing successfully!);catch(ArithmeticException e)System.out.println(ArithmeticException catched!);finally System.out.println(Finally block!);,异常的传播过程,如果没有catch语句块捕获异常,异常将沿着方法的调用栈一直向上传播。如果传播的过程一直没有catch语句块捕获,则最终传播到main方法,最后从main方法抛出,有JRE来处理,public class Testpublic static void main(String args)/在主方法中调用method1 method1();static void method1()/在method1中调用method2方法method2();static void method2()int a=new int3;a4=12;/产生下标越界异常System.out.println(ok!);,异常的分类,异常可分为:可控异常和执行时异常可控异常:即使程序本身没有问题,在某些情况下也可能发生比如:使用输入输出功能时,可能会由于硬件问题,使得程序无法正常从硬件取得输入或输出,这种错误是可以预期发生的。像这类异常称之为可控异常注意:Java规定:对于可控异常,编译器要求您必须进行处理!,补充例题,import java.io.*;public class Testpublic static void main(String args)tryBufferedReader buf=new BufferedReader(new InputStreamReader(System.in);System.out.println(请输入整数);int input=Integer.parseInt(buf.readLine();System.out.println(input=+input);catch(IOException e)System.out.println(I/O异常);catch(NumberFormatException e)System.out.println(输入必须为整数);,说明,IOException是可控异常,是可预期会发生的异常。编译器要求您必须处理!注意:异常一旦丢出就不会回到原点NumberFormatException是执行时异常。所谓的执行时异常就是发生在程序执行期间,并不一定可预测它的发生。且编译器不要求您一定要处理执行时异常。对于执行时异常若没有处理,则异常会一直往外丢,最后由JVM来处理,抛出异常,1 抛出异常语句2 抛出异常选项:throws,什么叫异常的抛出,如果某个方法里面有异常,并且没有被捕获,那么其会一层一层上报给调用者。,public class Testpublic static void main(String args)a();System.out.println(恭喜你,调用方法成功!);static void a()tryb();catch(RuntimeException re)System.out.println(异常在a方法被解决掉!);static void b()c();static void c()int a=new int3;a4=12;,小例题,1 抛出异常语句,程序员可以自己通过throw语句抛出异常。throw语句的格式如下:throw new 异常类名(信息)异常类名可以是系统异常类名,也可以是自定义的异常类名“信息”是可选信息。若提供了信息,toString()方法的返回值中将增加该信息的内容,例3,public class Exception3 public static int Sum(int n)if(n);catch(NumberFormatException e2)System.out.println(参数应为整数!);catch(IllegalArgumentException e3)System.out.println(错误参数:+e3.toString();finally System.out.println(程序结束!);,2 抛出异常选项,为了明确指出一个方法不捕获某类异常,而让调用该方法的其他方法捕获该类异常,可以在声名方法的时候,使用throws可选项,抛出该类异常。格式如下:修饰符返回值类型名 方法名参数表 throws 异常类型名 方法体,例4抛出异常方法,public class Exception4 public static int Sum()throws NegativeArraySizeException int s=0;int x=new int-4;for(int i=0;i 4;i+)xi=i;s=s+xi;return s;public static void main(String args)try System.out.println(Sum();catch(NegativeArraySizeException e)System.out.println(异常信息:+e.toString();,关于throws,方法头部分增加throws,而方法体里没有异常处理语句,若产生异常将自动抛出。对于这样的异常处理方式,我们称为“隐形抛出”,import java.io.*;import.*;public class Test/声明方法myFunction将有可能抛出IOException异常public static void myFunction()/throws IOException/创建ServerSocket对象ServerSocket ss=new ServerSocket(9999);public static void main(String args)/受监视的代码try/调用myFunction方法 myFunction();catch(IOException e)e.printStackTrace();System.out.println(恭喜你,程序正常运行结束!);,说明,与throw语句不同,throws选项仅需列出异常的类型名。,8.3.2 自定义异常,自定义异常类可以通过继承Exception类来继承。格式如下:class 自定义异常类名 extends Exception 类体,Exception类的几个常用方法,public void printStackTrace()该方法将在控制台打印异常调用栈的信息public String toString()该方法将返回该异常对象的字符串表示public String getMessage()返回异常对象中携带的出错信息,例5:自定义异常类,public class OverFlowException extends Exception OverFlowException()System.out.println(此处数据有溢出,溢出类是OverFlowException);,public class Exception5 public static int x=100000;public static int multi()throws OverFlowException int aim;aim=x*x*x;if(aim1.0E8|aim0)throw new OverFlowException();else return x*x;public static void main(String args)int y;try y=multi();System.out.println(y=+y);catch(OverFlowException e)System.out.println(e);,一个方法在声明时可以使用throws关键字声明要产生的若干个异常,并在该方法的方法体中具体给出产生异常的操作,即用相应的异常类创建对象,并使用throw关键字抛出该异常对象,导致该方法结束执行。程序必须在try catch块语句中调用能发生异常的方法,其中catch的作用就是捕获throw方法抛出的异常对象,8.3.2 自定义异常类,例8-5,public class BankException extends Exception String message;public BankException(int m,int n)message=入账资金+m+是负数或支出+n+是正数,不符合系统要求.;public String warnMess()return message;,public class Bank 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;System.out.printf(本次计算出的纯收入是:%d元n,netIncome);money=money+netIncome;public int getMoney()return money;,public class Example8_5 public static void main(String args)Bank bank=new Bank();try bank.income(200,-100);bank.income(300,-100);bank.income(400,-100);System.out.printf(银行目前有%d元n,bank.money);bank.income(200,100);/发生BankException异常,转向去执行catch bank.income(99999,-100);/没有机会被执行 catch(BankException e)System.out.println(计算收益的过程出现如下问题:);System.out.println(e.warnMess();System.out.printf(银行目前有%d元n,bank.money);,断言语句在调试代码阶段非常有用,断言语句一般用于程序不准备通过捕获异常来处理的错误使用关键字assert声明一条断言语句,断言语句有以下两种格式:assert booleanExpression;assert booleanExpression:messageException;其中booleanExpression必须是求值为boolean型的表达式;messageException可以是求值为字符串的表达式。,8.4断言,如果使用 assert booleanExpression:messageException;形式的断言语句,当booleanExpression的值是false时,程序从断言语句处停止执行,并输出messageException表达式的值,提示用户出现了怎样的问题;当booleanExpression的值是true时,程序从断言语句处继续执行。,使用断言,当使用java解释器直接运行应用程序时,默认为关闭断言语句,在调试程序时可以使用-ea启用断言语句,例如 java-ea mainClass,import java.util.Scanner;public class Example8_6 public static void main(String args)int score=-120,98,89,120,99;int sum=0;for(int number:score)assert number0:负数不能是成绩;sum=sum+number;System.out.println(总成绩:+sum);,