《Java核心技术》要点总结:接口与内部类,异常、日志与断言

接口

接口不是类,是一组对类的需求描述,这些类遵从接口描述的统一格式进行定义

接口中所有方法自动属于公有,声明时不必用public关键字修饰

类实现一个接口,需要:1. 将类用implements关键字声明为实现了给定的接口;2. 对接口中的所有方法进行定义,方法的访问权限需要是public

不能使用new实例化一个接口,但是能声明一个接口变量,接口变量必须引用实现了该接口的类的实例

instanceof关键字除了能检测一个类是否派生自另一个类,也能检测一个类是否实现了一个接口

类似继承,接口间也可以通过extends关键字进行扩展

接口中不能包含实例域或静态方法,但可以包含值域;接口中的域将被自动设为public static final,是为常量

Java中类不允许多重继承,但允许实现多个接口;接口本身与无具体域或具体方法的抽象类相似,但因为Java不允许多重继承,所以允许通过接口来实现多重继承的大部分功能

 

克隆

Object类中的clone方法(protected)生成一个各个域与原实例相同的“浅拷贝”新实例

浅拷贝:基本数据类型域和不可变的对象变量被赋予与原对象相同的值,但可变引用域与原对象引用的仍是相同的子对象;修改克隆对象中的引用对象,会影响原对象中的引用对象

深拷贝:基本数据类型域和不可变的对象变量被赋予与原对象相同的值,可变引用域与原对象中的引用域不再共享对象,而是重新创建新的、但内部数据相同的对象

对每个类,就克隆问题需要做如下判断:

1.      默认的clone方法(来自Object,浅拷贝)是否满足需求

2.      默认的clone方法是否能够通过调用可变子对象的clone得到弥补

3.      是否不应该使用clone

其中,3是必选的,1、2是可选的;若选择1、2,则:

1.      该类必须实现Cloneable接口

2.      使用public访问关键字重写clone方法

Cloneable是Java提供的几个标记接口之一,它不包含方法,只是用于instanceof检测时指明该类实现了它,进而表明该类重写的clone方法;若重写了clone而不实现它,则会在编译时产生异常

 

回调

回调是指出某个特定事件发生时应该采取的动作的一种设计模式

Java中采用接口来指定回调中需要执行的操作(方法);事件类(如定时器等)需要被传递一个实现了相应回调接口的类对象

在Java的事件处理中被广泛应用,如鼠标事件、键盘事件、端口监听等

 

内部类

定义在另一类之中的类;使用内部类的原因有三:

1.      内部类方法可以访问该类定义所在的作用域内的数据,包括私有数据

2.      内部类可以对同一个包中的其它类隐藏

3.      需要实现一个回调接口但不想写大段代码时,可采用匿名内部类

局部内部类:局部内部类是指定义在外围类的某一代码块(如方法块等)中的内部类;它不能用public或private修饰;其作用域也被限定在该代码块中;其好处是,不仅能访问外围类的所有域,而且被访问声明为final的局部变量(以保证局部变量与局部内部类中建立的变量拷贝保持一致),另外对于代码块外部,局部内部类是隐藏的

匿名内部类:创建一个实现了某接口或继承了某类的新类的新实例,需要实现的方法定义在实例后的{ }中;匿名内部类没有类名,不能有构造体;它可以将()括号中的参数传递给父类(如果有的话)的构造体,但当匿名内部类实现接口时不能有构造参数

静态内部类:静态内部类通过static关键字修饰,它只是为了把一个类隐藏在另一个类之中,但不需要在内部类中引用外围类的对象;声明在接口中的内部类将被自动设为public和static;静态方法中调用的内部类必须声明为静态内部类

 

异常

Java中,如果某个方法不能采用正确的运行途径完成它的任务,方法并不返回任何值,而是抛出一个封装了错误信息的对象,该方法会立刻退出,调用该方法的代码也将无法进行,而是进入异常处理机制

异常分类:所有的异常都继承自Throwable;Throwable派生了两个分支:Error和Exception:

Error类描述了Java运行时系统的内部错误和资源耗尽错误;Java应用不能抛出Error实例;如果系统抛出了Error,除了通知用户,尽力安全地终止程序外,别无他法

Exception类是Java程序设计中需要关注并处理的异常,分两类:RuntimeException和其它异常:

继承RuntimeException的异常类包含这些情况:错误的类型转换,数组访问越界,访问空指针

不继承它的异常类(即其它异常)包含这些情况:试图在文件末尾读数据,试图打开错误格式的URL,试图用给定的字符串查找不存在的类的Class对象

Java将Error和RuntimeException称为“未检查异常”,将其它异常称为“已检查异常”;编译器会自动核查已检查异常是否具有异常处理器,而未检查异常则需要在编程时予以检查和避免

声明已检查异常:以下4中情况会抛出异常:

1.      调用一个抛出已检查异常的方法

2.      在程序运行过程中发生错误,并且利用throw语句抛出一个已检查异常

3.      程序出现未检查异常的错误

4.      Java虚拟机和运行库出现的内部异常(Error)

若不对异常进行捕获和处理,必须在一个方法的首部(方法名处)声明所有可能抛出的已检查异常(通过throws语句);而未检查异常要么不可控(Error),要么应尽量避免其发生(RuntimeException),所以不需要声明

如果子类中覆盖了父类中的一个方法,那么子类方法中声明的已检查异常不能超过父类方法中声明的异常范围;即子类重写方法中声明的已检查异常集合不能必须是父类的子集

另外,声明要抛出的异常类可能是该类的一个实例,也可能是该类子类的一个实例

抛出异常:对于一个已存在的异常类:

1.      找到一个合适的异常类

2.      创建该类的一个实例

3.      通过throw关键字将其抛出

4.      在方法首部声明抛出了这个异常类

自定义异常类:对于尚不存在的异常类,则需要定义一个派生自Exception类或Exception类的子类的新异常类

捕获异常:如果某个异常发生的时候没有在任何地方捕获它,程序将会终止,并在控制台(或其它恰当的显示位置)打印异常信息,包括异常的类型和堆栈的内容

捕获异常必须设置try/catch语句块;一旦try语句块中的任何代码抛出了一个在catch字句指定的异常类,那么:

1.      程序将跳过try语句块中的其余代码

2.      程序将立即开始执行catch字句中的处理代码

如果调用一个抛出已检查异常的方法,要么通过throws声明将异常传递出去,要么通过try/catch对异常进行捕获和处理,否则编译器将报错

捕获多个异常:一个try语句块对应多条catch子句

再次抛出异常与链异常:在一个catch子句中,也可以抛出(throw)异常,这样做是为了改变异常的类型:将原本在try在发现的异常作为“诱饵”,在catch子句中通过Throwable(或其子类)对象的setCause方法,将原异常进行包装并抛出,重新捕获后通过getCause方法获取原始异常,从而达到改变异常类型而未丢失原异常细节的目的,如可以将某已检查异常包装成RuntimeException并抛出

finally子句:在同一个作用域内,不管是否有异常在try语句块中被捕获,不管catch子句是否再次抛出异常,finally子句中的代码都会被执行

若finally子句和try语句块中同时包含return语句,那么finally的返回值将会覆盖try的返回值

强烈建议单独使用try/catch和try/finally语句块,并将try/finally块放入try/catch块中,以确保finally子句中的异常也同样能被捕获,同时提高代码清晰度

 

日志

基本日志:默认日志记录器Logger.global

Logger.global.info(String log)方法可以记录日志信息,默认情况下,输出结果自动包含调用该方法的时间、类名、方法名以及日志信息log

高级日志:可以通过Logger Logger.getLogger(String logName)静态方法创建一个日志记录器对象;logName指定了该日志记录器的名字,通过同一个logName创建的是同一个日志记录器对象;logName字符串通过“.”划分层次结构(类似包名),高级别的日志记录器对象可以控制低级别对象的日志级别

日志级别(高到低):SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST

日志记录器对象通过setLevel(int)方法设置级别,如logger.setLevel(Level.INFO);另外,Level.ALL表示开启所有级别的记录,Level.OFF表示关闭所有级别的记录

添加日志记录的方法有warning(String)、info(String)、log(Level,String)等

更多日志信息的添加方法参见JavaAPI

日志管理器配置文件:位于jre/lib/logging.properties

处理器:默认的日志处理器是ConsoleHandler,它将日志输出到System.err流中

默认日志处理器的配置在配置文件中,也可以绕过配置文件设置其它的处理器,但要注意将useParentHandlers(boolean)方法置为false以免默认处理器和新处理器同时执行

日志API提供了两个处理器:

1.      FileHandler:日志记录收集到文件中,格式为XML

2.      SocketHandler:日志记录被发送到指定主机的指定端口

另外,还可以通过扩展Handler类或StreamHandler类自定义处理器

过滤器:可以通过实现Filter接口并定义boolean isLoggable(LogRecord)方法来自定义过滤器,在日志记录器对象中通过setFilter(Filter)方法来将过滤器安装到记录器中

 

断言

断言机制允许在测试期间向代码中插入一些检查语句;当代码发布时,这些插入的检测语句将会被自动移除;断言使用assert关键字,有两种形式:

1.      assert 条件

2.      assert 条件: 表达式

两种形式都会对条件进行判定,若为false,则抛出一个AssertionError异常;在第2种形式中,表达式将被传入AssertionError对象的构造体,并被转换成一个字符串,表达式存在的唯一目的就是产生一个字符串,AssertionError中并不保存表达式的值

启用和禁用断言:默认情况下,断言是禁用的

运行程序时,使用java命令的参数-enableassertions或-ea可以启用全部或某类、某包的断言;使用-disableassertions或-da可以禁用全部或某类、某包的断言

使用断言的时机:1. 断言失败是致命的、不可恢复的错误

                                      2. 断言检查只用于开发和测试阶段

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值