第七章 内部类和异常类
- [7.1 内部类](#7.1 内部类)
- [7.2 匿名类](#7.2 匿名类)
-
- [7.2.1 和子类有关的匿名类](#7.2.1 和子类有关的匿名类)
- [7.2.2 和接口有关的匿名类](#7.2.2 和接口有关的匿名类)
- [7.3 异常类](#7.3 异常类)
-
- [7.3.1 try-catch语句](#7.3.1 try-catch语句)
- [7.3.2 自定义异常类](#7.3.2 自定义异常类)
- [7.4 断言](#7.4 断言)
7.1 内部类
java支持在一个类中定义另一个类,这样的类称为内部类,而包含内部类的类称为内部类的外嵌类。
内部类与外嵌类的关系:
- 内部类的外嵌类的成员变量和方法在内部类仍然可用
- 内部类的类体中不能声明类变量和类方法,但是外嵌类的类体可以用内部类声明对象,作为外嵌类的成员
- 内部类仅供它的外嵌类使用,其他类不可以用某个类的内部类声明对象
使用场景:某种类型的农场饲养了一种特殊类型的牛,但是不希望其他农场饲用这种特殊类型的牛,那么这种类型的农场就可以创建这种特殊种类的牛的类作为自己的内部类
java
public class RedCowForm{
static 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 spead(){
System.out.println("我是"+cowName);
}
}//内部类结束
}//外嵌类结束
public class example{
public static void main(String args[]){
RedCowForm form = new RedCowForm("红牛农场");
form.showCowMess();
form.cow.speak();
}
}
注意,内部类的字节码文件名字格式为外嵌类名 内部类名 ' R e d C o w F o r m 内部类名 `RedCowForm 内部类名'RedCowFormRedCow.class`当把字节码文件复制给其他开发人员时候,记得把内部类的字节码文件都复制过去!!!
- 内部类是可以被修饰为static内部类的(外部类是不可以的)。这样一来,程序就可以在其他类中使用static内部类来创建对象了。但是需要注意的是,static内部类不能操作外嵌类中的实例成员变量。
java
RedCowForm.RedCow redCow = new RedCowForm.RedCow(180,119,6000);
redCow.speak();
7.2 匿名类
7.2.1 和子类有关的匿名类
java允许我们直接使用一个类的子类的类体创建一个子类对象,也就是说,创建子类对象时,除了使用父类的构造方法外还有类体,此类提被认为是一个子类去掉类声明后的类体,称作匿名类。匿名类不能声明对象,但是可以创建一个对象。
java
Bank a = new Bank(){
匿名类的类体
};
- 匿名类可以继承父类的方法,也可以重写父类的方法
- 匿名类一定是在某个类中用匿名类创建对象,匿名类一定是内部类。
- 与内部类相同,匿名类的类体不可以声明static成员,可以访问外嵌类的成员。
- 匿名类创建对象用的是父类的构造方法。
- 匿名对象的引用可以直接传递给一个匹配的参数
java
abstract class OutputAlphabet{
public abstract void output();
}
public class OutputEnglish extends OutputAlphabet{
public void output(){
for(char c = 'a';c<='z';c++){
System.out.println("%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()
{
public void output()
{
for(char = '1';c<='9';c++)
{
System.out.println("%3c",c);
}
}
});//为什么要这样呢?因为我们其实没有真正定义一个子类可以取输出数字,所以我们可以利用匿名类看成是一个子类,然后直接在里面重写父类的东西就可以。
}
}
7.2.2 和接口有关的匿名类
假设Computable是一个接口,那么java允许使用接口名和一个类体创建一个匿名对象,此类体被认为是实现了Computable接口的类去掉类声明后的类体,称作匿名类。
new Computable(){};
如果某个方法的参数是接口类型,那么可以使用接口名和类体组合创建一个匿名对象传递给该方法的参数,类体必须重写接口中的全部方法。
java
interface SpeakHello{
void speak();
}
class HelloMachine{
public void turnOn(SpeakHello hello){
hello.speak();
}
}
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!");
}
});
}
}
7.3 异常类
所谓异常就是程序运行的时候程序可能会出现的一些错误,Java使用throw关键字抛出一个Exception子类的实例表示异常发生。Java允许对象定义方法时候声明该方法调用过程中可能出现的异常,即允许方法调用过程中排除异常对象,终止当前方法的继续执行。
7.3.1 try-catch语句
java使用try-catch语句来处理异常,将可能出现的异常操作放在try语句中,一旦try部分抛出异常对象,或调用某个可能抛出异常对象的方法,并且该方法抛出了异常对象,那么try部分将立刻结束执行,转向执行相应的catch部分。
可以用下列语句输出与输出有关异常的消息。
java
public String getMessage();
public void printStackTrace();
public String toString();
java
try{
}
catch(ExceptionSubClass1 e){
}
catch(ExceptionSubClass2 e){
}
各个catch参数中的异常类都是Exception的某个子类,表明try部分可能出现的异常,这些子类之间不能有父子关系,否则保留一个含有父类参数的catch即可。
例子如下
java
public 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;
}
catch(NumberFormatException e){
System.out.println("发生异常" + e.getMessage());
}
try{
System.out.println("故意抛出I/O异常");
throw new java.io.IOException("我是故意的");
//System.out.println("这个输出语句肯定没机会执行,必须注释,否则编译出错");
}
catch(java.io.IOException e){
System.out.println("发生异常"+e.getMessage());
}
}
7.3.2 自定义异常类
在编写程序时候可以扩展Exception类(extends Exception)定义自己的异常类,然后根据程序的需要来规定哪些方法产生这样的异常。
一个方法在声明时候可以使用throws关键字声明自己要产生的若干个异常,并且在该方法的方法体中具体给出产生该异常的操作,即用相应的异常类创建对象,并使用throw关键字抛出该异常对象,导致该方法结束执行
程序必须在try-catch异常板块中调用可能发生异常的方法,其中catch的作用是捕获throw关键字抛出的异常对象
- 区分throw和throws,throw是用来抛出异常对象的关键字,throws是方法用来声明自己要产生的若干个异常。
下面是一个例子
java
public class BankException extends Exception{//这是自定义的一个银行异常
String message;
public BankException(int m,int n){
message = "入账资金" + m +"是负数或支出" + n +"是正数,不符合系统要求.";
}
public String warnMess(){
return message;
}
}
public class Bank{
private int money;
public void income(int in,int out) throws BankException{//定义该方法可能会产生的异常有哪些
if(in<=0||out>=0||in+out<=0){
throw new BankException(in,out);//方法抛出异常类,导致方法结束
}
int newIncome = in + out;
System.out.printf("本次计算出的纯收入是:%d元",newIncome);
money = money+newIncome;
}
public int getMoney(){
return money;
}
}
public class example{
Bank bank = new bank();
try{ //调用会抛出异常的方法,都要放在try中
bank.income(200,-100);
bank.income(800,-399);
bank.income(999,999);
}
catch(BankException e){
System.out.println("计算收益过程中出现如下问题");
System.out.println(e.warnMess());
}
System.out.printf("银行目前有%d元\n",bank.getMoney());
}
注意上面的finally语句,try-catch语句执行后会执行它,或者如果没有catch语句catch到也会执行它,如果catch没有捕获到,并且没有finally,程序会报错的
7.4 断言
断言语句在调试代码阶段很有用,断言语句一般用于程序不准备通过捕获异常来处理的错误,当发生某个错误的时候,希望程序立刻停止执行。
在调试阶段让断言代码发挥作用,可以发现一些致命错误,在程序正式运行的时候就可以关闭断言语句,但仍然可以把断言语句保存在源代码中,以后还可以用。
断言语句的语法格式
java
assert booleanExpression
assert booleanExpression:messageExpression
- 对于第一种的话例如
assert number>0
,如果true,程序继续执行,如果false,程序停止执行 - 对于第二种,和第一种不一样的是,他会输出messageExpression中的值
启动与关闭断言语句
当使用java解释器直接运行应用程序的时候,默认地关闭断言语句,在调试的时候可以使用ea启用断言语句
java -ea mainClass
例子
java
import java.util.Scanner;
public class example{
public static void main(String args[]){
int []score = {-120,98,89};
int sum =0;
for(int number:score){
assert number>0:"负数不能是成绩";
sum = sum+number;
}
}
System.out.println("总成绩"+sum);
}