关闭

Thinking in Java 笔记11-20

249人阅读 评论(0) 收藏 举报
分类:

12 Java的基本理念是 “结构不佳的代码不能运行”

12.2.1 异常参数
所有标准异常类都有两个构造器:一个默认构造器,一个接受字符串作为参数
能够抛出任意类型的Throwable对象,是异常类型的根基。

12.3.2
异常处理理论有两种基本模型:
终止模型:这种错误非常关键,以至于无法恢复。
恢复模型:修正错误

12.4 System.err不会被重定向

12.5 异常说明
throws语句用于说明方法可能会抛出的所有异常
如果方法里产生了异常却没有处理,那么编译器将会提示你:
处理这个异常
或在异常说明里表明方法会产生异常
这种在编译时被强制检查的异常被称作被检查的异常

12.6 重新抛出异常
重抛异常会把异常抛给上一级环境中的异常处理程序

12.7
RuntimeException如果没有被捕获而直达main,那么程序退出前将调用异常的printStackTrack方法

12.9 异常的限制
当覆盖方法的时候,只能抛出基类方法的异常说明里列出的那些异常。
异常限制对构造器不起作用
派生类构造器不能捕获基类构造器抛出的异常

12.12 其他可选方式
异常代表了当前方法不能继续执行的情形
重要原则 — 只有在你知道如何处理的情况下才捕获异常
一个目的 — 把错误代码和错误发生代码分离

12.13 异常使用指南
在下列情况使用异常:
在恰当级别处理问题(在知道如何处理情况下才捕获异常)
解决问题并重新调用产生异常的方法
进行少许修补,然后绕过异常发生的地方继续进行
用别的数据进行计算,以替代方法预计会返回的值
把当前环境能做的事尽量做完,然后把相同/不同的异常抛向更高层
终止程序
进行简化

让类库和程序更加安全

13.3
如果想要打印出对象的内存地址,应该调用Objects.toString方法
不应该使用this,而应该调用super.toString方法

13.5.3 Formatter类
Java所有新的格式化功能都由java.util.Formatter类处理。
当创建一个Formatter时,需要对其构造器传递一些信息,告诉它最终结果的输出位置

13.5.6 String.format方法
返回一个String
实际也是创建了一个Formatter对象
更加清晰易懂

13.6 正则表达式
String类内建功能
match方法
split方法

13.6.3 量词
贪婪型 — 尽可能多的匹配
勉强型 — 尽可能少的匹配
占有性(Java仅有)— 防止回溯,常用于正则表达式失控,可使正则表达式执行起来更加有效

13.6.4 Pattern和Matcher — 以后研究API

13.7.1 Scanner定界符
useDelimiter方法 — 传入一个正则表达式

hasnext方法也可以传入正则表达式来扫描

14.2 Class对象
包含了类有关的信息
每当编写并编译一个新类,就会产生一个Class对象
为了生成这个类的对象,运行这个程序的JVM将会使用类加载器这个子系统
包含一条类加载器链,但只有一个原生类加载器 — JVM实现一个部分
原生类加载器加载所谓的可信类
包括Java API类
当程序创建第一个对类的静态成员的引用时,就会加载这个类。
动态加载使能在C++这样的静态加载语言中是很难实现的活着根本不可能复制
类加载器首先检查Class对象是否加载。
如果尚未加载,默认的类加载器就会根据类名查找.class文件
这个类的字节码被加载时,会接受验证,确保其没有被破坏,并不包含不良Java代码
一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。
Class.forName方法是取得Class对象的引用的一种方法。
副作用 — 如果要求加载的类还没加载就加载,在加载中,其static字句就被执行
如果找不到类则抛出ClassNotFoundException
Class.forName不需要你有一个对象引用就能创建Class对象
getClass方法通过该类型对象引用返回Class对象
属于Object类一部分。

14.2.1 类字面常量 — XXX.class
第三种获得Class对象的引用的方法
安全,简单,高效
编译时受到检查
不仅可以应用于普通的类,还可以应用于接口,数组以及基本数据类型
对于基本数据类型的包装类,还有标准字段TYPE — 一个引用,指向对应数据类型的Class对象
原生数据类型.class == 对应包装类类型.TYPE
建议使用.class形式 保持一致性
为使用类而做的准备工作包含3个步骤
加载
类加载器执行
查找字节码
创建Class对象
链接
检验类的字节码,为静态域分配存储空间
如果必需,解析类创建的对其他类的所有引用
初始化
如果类有超类,则对其初始化
执行静态初始化器和静态初始化块
被延迟到对静态方法或者非常数静态域进行首次引用时执行
使用.class语法来获得类的引用不会引发初始化。
Class.forName方法立即进行初始化。
如果一个static final值是一个编译期常量,不需要初始化就可以读取
如果域设置为static和final,还不足以确保这种行为,因为它还不是一个编译期常量
如果是static而不是final的,那么对它进行访问时,就要进行链接和初始化

14.2.2 泛化的Class引用
普通的类应用不会进行类型检查,只要是Class类型就行
然而泛化的Class则能够进行类型检查
泛化的Class引用优于非泛化的
向Class引用添加泛化语法的原因仅仅是为了提供编译期类型检查
Class

final域在遭遇修改时是安全的。运行时系统会在不抛异常的情况下接受任何修改尝试,但是实际上不会发生任何修改

15.2 简单泛型
与其使用Object,我们更喜欢暂时不指定类型。

15.2.1 元组类库
元组 — 将一组对象直接打包存储于其中的一个单一对象。
允许读取其中元素
但不允许向其中存放新的对象
也称为数据传送对象或行使

15.3 泛型接口
泛型也可以应用于接口
可以在类中包含参数化方法 所在类也可以是泛型类,或不是。
指导原则:
无论何时,只要能做到,你就应该尽量使用泛型方法
如果使用泛型方法可以取代将整个类泛型化,那么就应该使用泛型方法,因为可以使事情更加清楚明白
对于static方法,无法访问泛型类的参数类型
如果要使static方法需要使用泛型能力,就必须使其成为泛型方法
要定义泛型方法,只需将泛型参数列表置于返回值之前

15.4.2 可变参数与泛型方法
泛型方法与可变参数列表很好共存

15.5 匿名内部类
泛型还可以应用于内部类以及匿名内部类

15.6 构建复杂模型
泛型的一个重要好处是能够简单而安全地创建复杂的模型
类型安全 可管理

15.7 擦除的神秘之处
不能声明泛型类实现后的类型的Class对象
getTypeParameters能够得到参数类型的信息,但只是参数占位符
在泛型代码内部,无法获得任何有关泛型参数类型的信息
Java的泛型是使用擦除实现的
任何具体的类型信息都被擦除了
运行时都被擦除为相同的类型
协助泛型类
给定泛型类的边界
泛型类型只有在静态类型检查期间才出现,在此之后,程序中的所有泛型类型都将被擦除,替换为它们的非泛型上界
擦除的核心动机是它使得泛化的客户端可以用非泛化的类库,vice versa — 迁移兼容性

15.7.3 擦除的问题
不能用于显式地引用运行时类型的操作
转型
instanceof
new
因为擦除在方法体中移除了类型信息,所以在运行时的问题就是边界

15.8 擦除的补偿
通过显示传递并保存Class。通过Class.isInstance方法动态比较
可以声明泛型数组 不过还是擦除了

15.9 边界
可以有多个上界 用& 连接

15.10 通配符
?unknown
extends
super 逆变
区别为通配符对于所持对象的表述差别
捕获转换
编译器可能会推断出实际的类型参数,使这个方法可以回转并调用另一个使用这个确切类型的方法

15.11 问题
任何基本类型都不能作为类型参数
实现参数化接口
一个类不能实现同一个泛型接口的两种变体
转型和警告
使用带有泛型类型参数的转型或instanceof不会有任何效果
要使用cast方法转型Class
重载
擦除原因
基类劫持了接口

15.12 自限定的类型 Class A extends SelfBounded{}
保证类型参数必须与正在被定义的类相同

15.12.3 参数协变

15.13 动态类型安全
将导出类型的对象放置到将要检查基类型的受检查容器是没问题的

15.14 异常
catch语句不能捕捉泛型类型的异常,因为在编译期和运行时都必须知道异常的确切类型

15.15 混型
泛型类不能直接继承自一个泛型参数

15.16 潜在类型机制
通过泛型(方法)来实现鸭子类型是可以的 接口,类也可以
补偿机制:
反射

将一个方法应用于序列

16 数组和其他种类的容器之内的区别
效率
效率最高的存储和随机访问对象引用序列的方式
访问非常快
代价是数组大小被固定
类型
可以持有基本类型
保存基本类型的能力

16.5 数组与泛型
数组与泛型不能很好结合,不能实例化具有参数化类型的数组
但是可以参数化本身的类型

16.6 创建测试数据
Arrays.fill()方法
数据生成器 Generator

16.7 Arrays功能
16.7.1 复制数组
System.arraycopy
比较
Arrays.equals
comparable/comparator
排序
正排序优化 — 对基本类型采取了Qsort
针对对象设计的“稳定归并排序”
在已排序的数组中查找

Arrays.binarySearch

17.2 填充容器
Collections.nCopies方法
Collections.fill方法
一种Generator解决方案
使用Abstract类
提供了容器的部分实现

17.3 Collection的功能方法
Map不是继承自Collection的
功能方法
add
addAll
clear — optional
contains
containsAll
isEmpty
iterator
remove
removeAll
retainAll
size
toArray

17.6.1 SortedSet
元素可以保持处于排序状态

17.7 队列
Queue
PriorityQueue
ArrayBlockingQueue
ConcurrentQueue
LinkedBlockingQueue
PriorityBlockingQueue
LinkedList

17.8理解Map
HashMap — 散列表实现
TreeMap — 红黑树
LinkedHashMap
WeakHashMap
ConcurrentHashMap
IdentityHashMap

17.9 散列与散列码
自反性
对称性
传递性
一致性
对不是null的x,x.equals(null)都应该等于 false

17.11 实用方法
查Collections API
unmodifiable系列方法生成只读Collection或Map
快速报错

17.12 持有引用
可获得性:
SoftReference > WeakReference > PhantomReference
User Case:
想继续持有对某个对象的引用,希望以后还能访问到该对象,但是也希望能够GC释放它
SoftReference 用以实现内存敏感的高速缓存
WeakReference 为实现“规范映射”而设计 不妨碍GC回收映射的Key或Value
规范映射中对象的实例可以在程序的多处被同时使用
PhantomReference用以调度回收前的清理工作,它比Java终止机制灵活
实用SR/WR时,可以选择是否要将它们放入ReferenceQueue

PR只能依赖于ReferenceQueue

18.1 File类
File既可以代表特定文件的名称,又能代表一个目录下的一组文件的名称
如果它指的是一个文件集,可以调用list方法返回一个字符数组
实际上FilePath应该是更好地名字
还可以搭配FileNameFilter接口使用

18.2 输入和输出
流 — 代表任何有能力产出数据的数据源对象或有能力接受数据的接受端对象。
屏蔽了实际IO设备处理数据的细节
可以通过叠合多个对象来提供所期望的功能

18.2.1 InputStream类型
用来表示那些从不同数据源产生输入的类
数据源:
字节数组 — ByteArrayInputStream
String对象 — StringBufferInputStream
文件 — FileInputStream
管道 — PipedInputStream
一个由其他种类的流组成的序列,以便把它们收集合并到一个流内
SequenceInputStream
将多个InputStream转换为一个InputStream
FilterInputStream
抽象类,做装饰器的接口
DataInputStream
BufferedInputStream
LineNumberInputStream

18.2.2 OutputStream类型
除了无StringBufferInputStream,其他类似

18.3.2 通过FilterOutPutStream向OutPutStream写入
DataOutputStream
可以将各种基本数据类型和String对象格式化输出到流
PrintStream
以初始化格式打印所有基本元素类型和String
BufferedOutPutStream
对数据流使用缓冲技术
输入/出的时候不是每次都进行实际的物理读写动作

18.4 Reader和Writer
兼容Unicode与面向字符的I/O功能

18.4.2 更改流的行为
PushbackReader

18.5 RamdomAccessFile
适用于大小已知的记录组成的文件
类似于把DataInputStream/DataOutPutStream结合起来,再加上一些方法

18.6.1 缓冲输入文件
BufferedReader支持readLine

18.10 NIO
具体查看NIO API

18.10.7
tryLock是非阻塞的
lock是阻塞的
fileLock可以实现对文件部分加锁

18.11 压缩
InputStreamReader/OutPutStreamWriter可以进行两种模式的切换
压缩类
CheckedInputStream
GetCheckSum方法为任何InputStream产生校验和(不仅压缩)
DeflaterOutputStream/InflateInputStream
基类
GZIP/ZipOutPutStream
将数据压缩成Zip/Gzip格式
了解API或第三方类库
JAR
了解jar

18.12
实现了Serializable接口的对象可以转化为一个字节序列
可以通过实现Externalizable接口代替实现Serializable
通过构造器构造然后执行extern方法
transient关键字
用于在序列化时关闭特定序列化字段

18.13 XML
自学第三方类库

18.14 Preference
和对象序列化相比对象持久性更密切
可以自动存储和读取信息
只能用于小的 受限的数据集合
基本类型和字符串
字符串不能超过8K

通常是创建以你的类名命名的单一节点,然后将信息存于其中

19.1 enum特性
ordinal方法返回声明时的次序
name方法返回enum特例声明时的名字
valueOf根据给定的名字返回enum实例 不存在则抛出异常

19.1.1 将静态导入用于enum
可以静态导入enum

19.2 向enum提交方法
enum元素也可以使用构造器
也可以覆盖enum的方法

19.3 switch语句中使用enum

19.4 values方法的神秘之处
enum都继承于Enum类
values方法是由编译器添加的static方法
同样的还有valueOf方法
如果把enum向上转型为Enum,就不能使用values方法了
Class.getEnumConstants方法依然可以获得所有enum实例

19.5 实现,而非继承
不能再继承enum了
但可以实现接口

19.7 用接口组织枚举
可以通过在构造器使用Class.getEnumConstants来得到枚举的枚举
也可以让一个enum镶嵌在另一个enum实现

19.8 使用EnumSet/EnumMap
自己看API

19.10 常量相关的方法
允许为enum编写方法

要为enum定义一个或多个抽象方法

20 Java内置注解
@Override
当前方法定义将覆盖超类中的方法
@Deprecated
如果程序员使用了注解为它的元素,会发出警告
@SuppressWarnings
关闭不当的编译器警告信息。

20.1.1 定义注解
@Target用来定义你的注解应该用于售卖地方
@Rectetion用来定义该注解在哪个级别可用
SOURCE
CLASS
RUNTIME
没有元素的注解被称为标记注解
注解的元素使用时表现为名-值对形式,

20.1.2 元注解
@Target
ElementType
CONSTRUCTOR
FIELD
LOCAL_VARIABLE
METHOD
PACKAGE
PARAMETER
TYPE — 类 接口(包括注解) enum
@Retention
RetentionPolicy
SOURCE — 注解被编译器抛弃
CLASS — 被VM抛弃
RUNTIME — 在运行期被保留
@Documented
此注解被包含在Javadoc中
@Inherited
允许子类继承父类中的注解

20.2
getAnnotation返回指定类型的注解对象

20.2.1 注解元素
注解元素可用的类型
基本类型
String
Class
enum
Annotation
以上类型的数组
注解可以为元素类型,注解也可以嵌套

20.2.2 默认值限制
元素必须要么有默认值,要么在使用注解时提供元素的值
对于非基本类型,都不能以null作为其值

20.2.4 注解不支持继承

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:5492次
    • 积分:253
    • 等级:
    • 排名:千里之外
    • 原创:20篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类