第七章 内部类与异常类
7.1 内部类
在一个类(设为类1
)中定义另一个类(设为类2
)。类2
就叫做内部类
,类1
叫做外嵌类
。
- 内部类与外嵌类的关系:
外嵌类对内部类:
- 外嵌类中可以声明内部类的示例对象作为自己的成员变量。且如果外嵌类要访问内部类,需要通过内部类的实例对象访问。
内部类对外部类:
- 内部类可以访问到外嵌类的成员变量和成员方法。
- 内部类仅供它的外嵌类使用,其他类不可使用某个类的内部类声明对象。
- 内部类的一些特性:
- 内部类的类体中不可以声明静态成员和静态方法。
- 一般的类有 p u b l i c public public和 友好的 \text{友好的} 友好的两种访问修饰符,内部类可以有四种访问修饰符 p u b l i c public public, p r o t e c t e d protected protected, 友好的 \text{友好的} 友好的, p r i v a t e private private。但是由于内部类仅供外嵌类使用,对内部类的访问修饰符一般无效。
- j a v a java java编译器生成的内部类字节码的文件名格式为:$\text{外嵌类名$内部类名}.class$。
- 如何打破内部类仅供外嵌类使用的限制
可以将内部类声明为静态类,即加上修饰符 s t a t i c static static。此时内部类会作为外嵌类的一种静态数据类型。由此便可以使用内部类在别的类中声明实例对象。
注意:非内部类不可以是 s t a t i c static static类。
7.2 匿名类
主要是2个方面:和子类有关的匿名类
、和接口有关的匿名类
。
用Lambda表达式代替匿名类
与函数接口与Lambda表达式
相差不大,不做记录。
- 和子类有关的匿名类
当没有给出子类的定义时,想声明子类对象,那么就需要通过匿名类。
匿名类的特点:
- 承接上一小节:匿名类一定是内部类。因为 j a v a java java是完全面向对象的语言,匿名类一定是在另外一个类中出现的。
- 由于匿名类是内部类,所以匿名类中不能有 s t a t i c static static成员和 s t a t i c static static方法。
- 匿名类无名字,也无构造方法,所以需要借用父类构造方法创建对象。如Bank为一父类。创建子类对象: n e w B a n k ( ) { 匿 名 类 的 类 体 } new\ Bank()\{匿名类的类体\} new Bank(){匿名类的类体}
- 匿名类可以继承和重写父类方法。
- 匿名对象的引用可以传给匹配的参数,比如:其父类的对象变量。这里可以是: B a n k b a n k = n e w B a n k ( ) { 匿 名 类 的 类 体 } ; Bank \ bank\ =\ new\ Bank()\{匿名类的类体\}; Bank bank = new Bank(){匿名类的类体};
- 编译器会给匿名类一个名字。虽然匿名类无名,但是编译器会给匿名类一个类名,可以通过匿名类实例对象的
getClass()
方法来得到该对象的类名。匿名类的类名格式为外嵌类类名$数字
。对于匿名类,其外嵌类即为匿名类体所在的类。
为了验证第6点,这里给出一段代码:
package chap7;
class ClassOne{
InnerClass incls;
ClassOne(){
incls = new InnerClass();
}
public void speak() {
System.out.println("Hello");
}
class InnerClass{
int height;
public void say() {
System.out.println("ok");
}
}
}
public class Hidename {
public static void main(String[] args) {
// TODO 自动生成的方法存根
ClassOne cls1 = new ClassOne();
System.out.println(cls1.getClass());
ClassOne cls2 = new ClassOne() {
public void speak() {
System.out.println("这是第一个匿名类");
}
};
System.out.println(cls2.getClass());
ClassOne cls3 = new ClassOne() {
public void speak() {
System.out.println("这是第二个匿名类");
}
};
System.out.println(cls3.getClass());
System.out.println(cls1.incls.getClass());
}
}
运行结果如下:
class chap7.ClassOne
class chap7.Hidename$1
class chap7.Hidename$2
class chap7.ClassOne$InnerClass
- 和接口有关的匿名类
j
a
v
a
java
java允许直接使用接口名
和类体
创建一个匿名对象。假设
C
o
m
p
u
t
a
b
l
e
Computable
Computable是一个接口:
new Computable(){
实现接口的匿名类的类体
}
Computable com = new Computale(){
实现接口的匿名类的类体
}
这里匿名类的类体必须重写接口的全部抽象方法。
- Lambda表达式代替匿名类
略
匿名类的实例对象一般作为参数被传递。在本书中,主要用于事件响应。
7.3 异常类
关于异常,此处仅做简单记录。
异常
:所谓异常就是程序运行时可能出现的一些错误。
-
错误:当程序不能正常运行或者运行结果不正确时,表明程序中有错误。按照错误的性质可将程序错误分成3类:
语法错
、逻辑错
、运行时错误(语义错)
。-
语法错:违反语法规范的错误。一般编译时会被编译器指出。在
IDE
中一般会在程序编写的过程中指出。 -
逻辑错:程序可以通过编译并运行。但是运行结果不符合预期。这种错误一般只能通过程序员的经验修改。
-
运行时错误:也叫做
语义错
。程序在语法上正确,但是在运行过程中会报错。如:除数为0,数组下标越界,变量赋值超过其数据类型的表示范围等。语义错又有两种:
- 能够被程序事先处理:比如,除数为0,数组下标越界等,我们可以通过
if语句
来事先判断。 - 不能被程序事先避免的:比如,程序崩溃,网络连接中断,打开文件不存在等。
语义错还有一种划分方式:
错误(Error)
:指程序运行时遇到的硬件或操作系统的错误。如内存溢出、虚拟机错误,系统崩溃等。错误对程序而言是致命性的,导致程序无法运行,只能依靠外界干预。异常(Exception)
:指在硬件和操作系统正常时,程序遇到的运行错,如整数进行除法运算时除数为0,或操作数超出数据范围,或打开一个文件时发现文件不存在,或网络连接中断等。异常对程序非致命,能导致程序终止。但 j a v a java java的异常处理机制可以处理异常,让程序继续运行。
- 能够被程序事先处理:比如,除数为0,数组下标越界等,我们可以通过
-
try-catch-finally语句
语法规范:
try{
运行语句块(包含可能会发生异常的语句)
}
catch(ExceptionSubClass1 e){
}
catch(异常类名 异常类对象名){
}
finally{
}
在try语句块
中,一旦遇到throw
抛出的异常,那么后面的语句都不会执行。
catch子句编写顺序
:一旦在try语句块中抛出异常,那么会按照catch子句的编写顺序从上到下依次匹配,如果抛出异常的类型
是catch子句参数的类型
或其子类
,则异常被该catch子句捕获
。
因此,异常类的子类应该尽可能的写在父类的前面,否则子类catch代码段将永远不可达。
-
catch子句异常捕获规则:
- 捕获异常与catch子句类型相同。
- 捕获异常是catch子句类型的子类。
- 一个异常被多个catch子句匹配时,按语句顺序匹配第一个。
-
关于
finally
:
在try-catch
语句执行后,程序便会执行finally
语句块。不管try是否抛出了异常,finally都会被执行。
这里有两个特殊情况:
- 如果在
try-catch
语句中执行了return
语句,那么finally
语句仍然会被执行。注意return
出现在try
语句块中还是出现在catch
语句块中,最后finally
都会执行。 - 如果在
try-catch
语句中执行了程序退出代码,即执行了System.out.exit(0);
,则不会执行finally
子句(当然也包括System.out.exit(0)
之后的所有代码)。
自定义异常类
我们可以自己定义异常类,自己定义的异常类继承自其他异常父类。比如Exception
等。
同时我们可以指定哪些方法可以跑出哪些异常,这需要使用关键字throws
。注意throws
与throw
的区别。
throw
是在程序中指定抛出一个异常类的对象,这个对象一般被用来捕获。
throws
是指定某个方法可以跑出哪些类
。比如:
public void fun() throws Exception1,Exception2,Exception3{
}
如果一个方法可以跑出多个异常类,这些类之间用逗号分隔开。
断言
语法格式:
assert booleanExpression;
assert booleanExpression:messageException;
booleanExpression
为布尔表达式,如果结果为true,则程序继续执行,为false,程序停止。
messageException
:为一表达式。当断言结果为false时,程序停止,并输出messageException
表达式的值。
- 启用断言:
java -ea 主类名
这里的-ea
参数表示开启断言。
参考资料
[1] java2 实用教程(第六版)(耿祥义 张跃平 主编)