序号
|
内容
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
常量
final int SOCKS = 3;
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
collection-based for
for(type identifier : iterable_expression)
{
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
continue
、
break
可以带标号
Loop:
for()
{
continue Loop;
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
断言
P101
(1)
适用情况:一旦执行了某些语句,意味着程序或者环境有十分严重的错误
(2)assert true;
程序继续执行
assert false :
错误信息
;
程序终止,并输出
java.lang.AssertionError
的错误
(3)
运行时使用
-ea
开启断言,否则断言将被忽略
(4)if (daysInMonth == 31 || daysInMonth == 30 || days InMonth == 29 || daysInMonth == 28)
{
//
正常情况
}
else
{
assert false :
错误:当月天数为
+ daysInMonth;
}
assert false/true;
assert false/true : string;
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
多维数组,不同维度的数组长度可以不同
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6
|
字符串变量值是对字符串本身的引用
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
基本数据类型转换成字符串,是在其包装类中的静态方法
.toString()
完成的
如:
10 + is a number
实际上是通过
Integer.toString(10) + is a number
完成的。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8
|
等值比较
“==”
可以用于基本数据类型的比较,但用于对象比较时会出现问题,因为对象变量值是对对象本身的引用,即使对象的各种属性值都相同,在内存中是两个地址的话,那么用
==
判断只是比较两个地址的值,是不相等的。典型情况是
String
的等值判断要用
equals()
。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9
|
扣留
.intern()
将
String
对象本身的值与其他
String
对象的值进行对比,一样的话则丢弃当前
String
对象,而对象变量是对原来相同字符串的引用,这使得
==
同样起作用,一般来说不要使用
.intern()
,而且使用
equals()
进行相等判断。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
10
|
split
分隔符要写在
[]
中,如
[,.]
表示使用
,
和
.
分隔。重载方法的第二个参数
<0
则返回最后的空标记;
=0
则不返回。不带有第二个参数的方法,是表示
=0
的情况。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11
|
内存中仅有一个实例方法的副本,该类的所有对象均调用这一个方法。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
12
|
所有参数都是指传递
对于基本数据类型会传递实参的副本,对于对象会传递对象变量的副本,但也能通过副本对象应用到对象本身。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
13
|
将参数定义为
final
,可以防止实参的值被修改。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
14
|
静态初始化块
静态变量最好由静态块初始化
static int[] values;
static
{
values = new int[10];
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
15
|
垃圾回收
System.gc();
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
16
|
在构造函数中调用另外一个构造函数
constructor()
{
int a = 0;
this(a);
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
17
|
根据已有对象建立对象的深拷贝
P176
Sphere(static Sphere oldSphere)
{
//
构造函数
radius = oldSphere.radius;
xCenter = oldSphere.xCenter;
yCenter = oldSphere.yCenter;
zCenter = oldSphere.zCenter;
++Count;
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
18
|
在需要的情况下,实现
toString()
方法
public String toString()
{
//...
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
19
|
编译的时候可以使用
“-classpath
包所在路径
” P186
一般用
javac -classpath .;package path *.java
,
package path
是包所在的上级目录,“
.
”为当前路径
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
20
|
CLASSPATH
访问包
可以在
CLASSPATH
环境变量或
java -classpath
中指定
package
所在目录。编译和运行的时候都可能需要制定
classpath
。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
21
|
JAVA_HOME/jre/lib/ext/
中存储着扩展包,这里的包会自动访问到,而不用设置
-classpath
。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
22
|
打包
jar cvf Geometry.jar Geometry/*.class
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
23
|
基本数据类型到对应的包装类的转换是由自动装箱
/
拆箱完成的。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
24
|
访问属性
default
包内
public
所有
private
类内
protected
包内、子类
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
25
|
对私有成员的访问
P194
访问器
accessor
方法,形如
getXXX();
增变
mutator
方法,形如
setXXX();
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
26
|
嵌套类
nested class P199
·嵌套类是外部类的成员,并且有自己的访问属性
·嵌套类用于:定义与其外部类的对象有很强关联的对象;在外部类中对有关联的类进行分组
·嵌套类的可见域
P201
class Outside
{
static members
static class Skinside
{
static members
non-static members
}
class Inside
{
non-static members
}
non-static members
}
·嵌套类生成的
class
文件名为“外部类名
$
嵌套类名
.class
”
·在顶层类之外使用嵌套类
静态嵌套类:
new
外部类名
.
嵌套类名
();
非静态嵌套类:外部对象
.new
嵌套类名
();
·何时使用静态嵌套类?当嵌套类中需要定义静态成员时
·局部嵌套类
在方法中定义嵌套类,并且只能在该方法中使用局部嵌套类,局部嵌套类可以访问方法中的
final
变量
适用于方法中的计算要求使用一种特殊类,而这个类在别的地方并不需要,比如事件监听器
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
27
|
finalize()
方法
P206
在对象销毁前调用,但对象的销毁时机由
JVM
控制,因此对时间敏感的处理不应该放在
finalize()
方法中
可以使用
System.gc()
和
System.runFinalization()
方法调用
JVM
进行垃圾回收
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
28
|
本地方法
P207
在类中可以包含一些其他编程语言,在方法声明时使用
native
关键字,适用本地方法将使程序丧失可移植性,
applet
处于安全考虑不允许使用本地方法
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
29
|
隐藏数据成员
P212
当派生类的数据成员的名称与基类的数据成员的名称相同时,基类的成员都会被隐藏起来,但仍可以使用
super.
访问基类成员
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
30
|
继承时的构造函数
P212
构造函数不能被继承
编译器会在派生类的构造函数的第一条语句前插入
super();
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
31
|
覆盖基类方法
P215
派生类的方法需要和基类的方法有相同的签名,访问属性一致,或者在派生类中的限制更少
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
32
|
通用基类
Object P222
·
toString()
返回“类名
@
对象的散列码”
·
getClass()
每个类或者接口都只有一个
Class
对象,因此可以使用“对象
.getClass() ==
类
.class
”进行精确验证“对象”是否是“类”类型的,并且忽略继承关系
·
clone()
当实现
Cloneable
接口时才可以进行对象的复制
Object.clone()
将生成一个与当前对象类型相同的新对象来实现复制,并把新的对象中的每个成员域都设置成与当前对象的对应成员域相同的值,因此当原始对象的数据成员引用一个类对象时,类对象在
clone
时不会被复制,而只是复制引用
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
|
可变实参方法
P229
方法定义为“方法名
(
参数类型
args)
”
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
34
|
instanceof P234
instanceof
比较左侧对象与右侧操作数,类型相同或者是它的子类则返回
true
对象
.getClass() ==
类
.class
则进行类型精确比较
当进行类强制转换之前使用
instanceof
进行判断
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
35
|
枚举
P235
·枚举也是一种类,自定义枚举继承了
java.lang.Enum
类
·默认情况下,枚举中的每个常量都分配一个正数值,按照定义顺序
0
开始赋值,可以使用
ordinal()
获取这些值,
compareTo()
方法也是使用该值进行比较的
·添加成员
可以像普通类一样给枚举定义成员变量和成员方法,但构造函数不能定义为
public
类型,因为它只能在枚举类的内部使用,如果需要改变枚举常量的输出显示,覆盖基类的
toString()
方法
public enum
枚举类名
{
枚举常量
1, //
枚举类的一个实例
枚举常量
n; //
逗号分割枚举常量,分号结束
其他成员,如构造函数等
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
36
|
类的设计
P238
两种情况:层次结构的类,反映“是
is a
”关系;包含类对象的类,反映“有
has a
”关系。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
37
|
final
P248
用
final
标记方法时,则这个方法在派生类中不能被覆盖,但抽象方法不能标记为
final
,因为它必须在派生类中实现
用
final
标记类时,则这个类不能被继承,类似
.net
中的密封类
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
38
|
公共常量的访问
P249
使用接口(过时):可以使用“接口
.
常量”访问或在实现接口的类中直接访问接口常量
使用类(时髦):使用“类
.
常量”访问或在源文件中使用“
import static
类名
.
常量”引入常量
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
39
|
clone()
方法
P254
Object.clone()
方法的访问属性是
protected
,
Cloneable.clone()
的访问属性是
public
,因此一个类想要含有克隆方法,必须实现
Cloneable
接口,以获得
clone()
方法的
public
访问属性,在代码中使用下面的方法
public Object clone()
{
return super.clone(); //
这里实际上调用了
Object
的
clone()
方法
}
不甚了了
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
40
|
接口
P248
·接口是一组相关常量和抽象方法
·接口中的方法默是
public
和
abstract
类型,常量总是
public static final
类型,不应该去改变它们
·实现接口中定义的全部方法的类可以实例化,实现接口中定义的部分方法的类是抽象类
·接口可以进行扩展,使用
extends
关键字继承超接口即可,接口可以多重继承(同时继承多个接口)而类不可以
·接口的重要意义,为实现相同接口的类产生多态,而不局限于类于子类之间。虽然不能生成一个接口对象,但是可以定义一个接口类型的变量,使用它来存储实现接口的任何类型的对象的引用,也就意味着可以使用这个变量来多态调用在接口中声明的方法,也可以把方法的形参定义为接口类型
·在接口中可以定义嵌套类,并且是
public static
类型的
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
41
|
匿名类
P262
当需要一个作为方法实参的对象,并且这个对象实现某个接口或者继承某个类时,可以使用匿名类,匿名类适用于定义简短的情况,比如
pickButton.addActionListener(new ActionListener()
{
//
实现
ActionListener
接口方法的代码
}
);
不甚了了
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
7
章
异常
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
使用异常的思想
P265
并非所有的错误都需要由异常来指出,异常指出的是可能出现的灾难情况,异常处理涉及到很大处理负担
Java
中异常是党程序出现不正常情况时生成的一个对象,这个异常对象具有存储问题信息的成员域
4
种可能抛出异常的情况:代码或者数据错误、标准方法异常、自定义异常、
Java
语言错误
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
异常类型
P265
Throwable
类是
Java
语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过
Java
虚拟机或者
Java throw
语句抛出。类似地,只有此类或其子类之一才可以是
catch
子句中的参数类型,她包含两个直接子类
Error
和
Exception
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
Error
类
P265
用于指示合理的应用程序不应该试图捕获的严重问题,又包含
ThreadDeath
、
LinkageError
、
VirtualMachineError
三个直接子类,对于
ThreadDeath
可以捕获它,进行清理工作,但必须要再次抛出这个异常,以销毁相关线程。而
LinkageError
、
VirtualMachineError
一般不需要捕获
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
RuntimeException
P266
一般来说,当程序中有可能会抛出异常时,必须对代码段做
try-catch
处理,或注明方法将抛出异常,但有一个例外——
RuntimeException
,
RuntimeException
允许编译器忽略它们,因为他们通常由代码中的严重错误产生。这将包含
ArithmeticException
、
IndexOutOfBoundsException
、
NegativeArraySizeException
、
NullPointerException
、
ArrayStoreException
、
ClassCastException
、
IllegalArgumentException
、
SecurityException
、
IllegalMonitorStateException
、
IllegalStateException
、
UnsupportedOperationException
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
多次
catch
P272
当需要多次
catch
时,把派生次数最多的类写在前面,而基础的在后面
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6
|
finally
的新用法
P273
允许存在
try-finall
形式的异常处理,
try
块中的代码可以不抛出任何异常。因为异常处理支持上面两点特性,因此可以用于处理下面的情况:当
try
块中有多个可能的退出点时(如多个
break
或
return
),希望在
try
代码块后总是执行一些语句,就可以将这些语句放到
finally
块中,但
finally
块中的返回值会覆盖掉原来
try
块中的返回值
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
执行域(
execution stack
)
P280
执行域跟踪在任何特定实例中运行的所有方法,为方法提供返回调用点的途径,生成产生异常时的行号,方法的调用记录
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8
|
Throwable
类
P280
·
getMessage()
显示异常信息
·
printStackTrace()
将栈的跟踪记录输出到标准错误输出流
·
printStackTrace(PrintStream s)
输出到指定的流,
printStackTrace()
等价于
printStackTrace(System.err)
·
fillInStackTrace()
记录异常点,常用于
catch(Exception e)
{
e.fillInStackTrace();
throw e;
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
8
章
流
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
缓冲流
P290
为了提高流传输数据的效率,为流配备一个大小合理的缓冲区,可以使传输过程更加有效,这样的流成为缓冲流
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
字符数据到流的转换
P290
向字节流写入字符或者从字节流读取字符,不会发生任何转换过程;但是在写字符流时,字符从
Unicode
字符码转换为字符的本地机器表示,读取时发生逆向转换
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
BufferedInputStream
P293
派生自
InputStream
的派生类
FilterInputStream
BufferedInputStream bis = new BufferedInputStream(InputStream, bufferSize);
默认情况下
bufferSize = 8kb
,
BufferedOutputStream
的作用与用法类似
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
InputStream
和
OutputStream
类
P295
字节流由
InputStream
类和
OutputStream
类的子类来表示,它们都是抽象基类,使用时应根据具体情况使用它们的派生类,字符流操作由
Reader
类和
Writer
类的子类提供
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
PrintWriter
的特点
P297
PrintWriter
对象的方法不会抛出异常,因此为了确定是否发生错误,必须调用
checkError
方法
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6
|
标准流
P298
标准输入流——
System.in
,
InputStream
类型,默认键盘
标准输出流——
System.out
,
PrintStream
类型,默认命令行
标准错误输出流——
System.err
,
PrintStream
类型,默认命令行
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
切分流
StreamTokenizer
P298
针对
Ascii
编码的单字节字符流进行切分,可以解析出数、单词、字符串、注释、空白,并且可以自行制定分割器,在定制之前,通常先调用
resetSyntax()
方法
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8
|
Printf
方法
P304
同样作用的还有
String.format()
方法和
Formatter
类
StringBuilder sb = new StringBuilder();
Formatter f = new Formatter(sb);
f.format("Today is %s", new Date());
System.out.print(sb);
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9
|
Locale
类
P308
定义语言环境,影响各种类型数据(如日期和货币)的表示方式,可以调用构造函数得到对象或调用
Locale
类的静态变量,而后一种方法更为常用
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
9
章
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
File
类
(
1
)
File
对象
P310
File
对象并不代表一个文件,它只是封装了路径名和引用,该引用指向的文件或目录可能不存在
(
2
)
File
对象的目的
P310
检查
File
对象引用的文件或者目录是否存在;创建文件流对象
(
3
)
File
的构造函数
P310
new File("
路径
"); //
路径并不一定有效
new File("
目录名
", "
文件名
");
new File(
目录
File
对象
, "
文件名
");
new File(URI
对象
);
(
4
)
File
对象的不变性
P311
一旦创建了
File
对象,就不能改变它所封装的路径,当使用
renameTo()
方法改变
File
对象所应用的文件或目录名称后,
File
对象指向的路径将不再有效
(
5
)
File
对象的方法
P315
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
路径常量
P312
路径可以分为三种形式:
绝对路径:包含前缀的路径,前缀在
windows
中如
"c:/"
,在
unix
中是
"/"
相对路径:相对于当前目录,如
new File("dir//Output.txt");
指当前路径下的
dir
文件夹下的
Output.txt
文件
UNC
(
Universal Naming Convention
,通用命名标准)路径:
windows
环境中如“
//
机器名
/
共享目录名
/
文件名”;非
windows
环境中如“
//
机器名
/
共享目录名
/
文件名”,即
File.separator + File.separator +
机器名
+ File.separator +
共享目录名
+ File.separator +
文件名
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
系统属性
P319
System.getProperties()
方法可以返回
java.util.Properties
类型的系统属性,其中
"user.dir"
定义了默认相对路径
"user.home"
定义了用户的主目录(如“
c:/Document and Settings/
登录用户名”)
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
FileDescriptor
(文件描述符)对象
P328
InputStream
和
OutputStream
对象通过
getFD()
方法返回
FileDescriptor
对象。它用作与基础机器有关的某种结构的不透明句柄,该结构表示开放文件、开放套接字或者字节的另一个源或接收者。文件描述符的主要实际用途是创建一个包含该结构的
FileInputStream
或
FileOutputStream
。这样就可以对一个文件同时获得多个输入、输出流,但不能同时获得输入和输出流
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
10
章
写文件
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
对文件的访问方式
P330
·顺序存取
·随机存取
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
JDK1.4
引入的文件
I/O
功能
P331
主要涉及到三个对象:
·文件流对象,包括
java.io.InputStream
和
java.io.OutputStream
·缓冲区对象,包括
java.nio.ByteBuffer
·通道对象:
java.nio.channels.*
,使用一个或多个缓冲区对文件进行读写
读文件和写文件的过程基本相同,写文件时,先将数据载入一个或多个缓冲区,然后调用通道对象的方法将数据写入到文件中。读文件时,先调用通道对象的方法,将数据从文件读入到一个或多个缓冲区中,然后从缓冲区中获取数据
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
通道
P332
(
1
)
JDK1.4
引入通道,它提供比流类的方法更快的输入、输出性能,输入、输出的对象包括文件、网络套接字和程序之间的管道
I/O
操作,通道机制可以充分利用缓冲区以及操作系统提供的其他功能
(
2
)通道的接口层次
Closeable
:可以关闭数据源或数据目的地
Channel
:与驱动器(如文件或套接字)的连接,继承
Closeable
InterruptibleChannel
:可异步中断的通道,继承
Channel
WritableByteChannel
:将数据从一个缓冲区写入驱动器的通道,继承
Channel
GatheringByteChannel
:将数据从多个缓冲区写入驱动器的通道,继承
WritableByteChannel
ReadableByteChannel
:将数据从驱动器读取到一个缓冲区的通道,继承
Channel
ScatteringByteChannel
:将数据从驱动器读取到多个缓冲区的通道,继承
ReadableByteChannel
ByteChannel
:将数据从单个缓冲写入到驱动器或从驱动器读取到单个缓冲区的通道,继承
WritableByteChannel
和
ReadableByteChannel
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
缓冲区
(
1
)视图缓冲区
P334
java.nio.Buffer
为基类,其派生类有
ByteBuffer
、
CharBuffer
、
ShortBuffer
、
IntBuffer
、
LongBuffer
、
FloatBuffer
、
DoubleBuffer
,只有
ByteBuffer
才能在文件
I/O
操作中使用,其他
6
种缓冲称为视图缓冲。
(
2
)缓冲区的属性
·容量
P335
指缓冲区能包含值的最大数量,而非字节数,一旦被初始化,就不能再改变
·位置
P336
指下一个将要访问(读取或写入)的元素的索引,类似文件指针,当顺序访问文件的时候,每次读取或写入元素,位置将自动增加
·边界
P336
缓冲区第一个不能读取或写入的值的索引,缓冲区允许
0 <=
位置
<=
边界
<=
容量,而默认值是
0 =
位置
<=
边界
=
容量
(
3
)方法
·
hasRemaining()
P338
将确定缓冲区位置和边界之间是否含有元素
·
remainging()
P338
将返回缓冲区从当前位置开始,还可以容纳多少个元素
·
allocate()
P338
静态方法,参数为缓冲区的容量,创建间接缓冲区,间接黄冲区独立于系统缓冲区,它使用系统缓冲,其间涉及到数据的复制,因此适合小容量的缓冲
·
allocateDirect()
创建直接缓冲区,它将直接分配系统缓冲区,它的分配和回收需要消多资源,因此适合大容量的缓冲
·
isDirect()
判断是否封装了直接缓冲区
·
asXXXBuffer()
从
ByteBuffer
对象的当前位置开始,到边界结束之间的元素,尽可能大的创建指定类型的视图缓冲区,新创建的视图缓冲区元素将和
ByteBuffer
对象中元素共享同一个内存空间,这也就是它被称之为“视图”的原因,新创建的视图缓冲区有独立的位置、边界,并且位置默认为
0
,边界默认为容量。一个
ByteBuffer
对象可以创建多个视图缓冲区,他们可以互相重叠。
·
duplicate()
P340
复制缓冲区,复制后的缓冲区中元素将和原缓冲区中元素共享同一个内存空间,复制后的缓冲区有独立的位置和边界,但复制后的缓冲区位置和边界初始值与原缓冲区的相同
·
slice()
P341
划分缓冲区,其结果是将原缓冲区中当前位置到边界之间的元素引用到新的缓冲区,新缓冲区有独立的位置和边界,位置初始值为
0
,边界为新缓冲的容量
·
wrap()
P341
静态方法,从数组对象创建缓冲区对象,创建后的缓冲区元素将和数组元素共享同一个内存空间
创建
CharBuffer
,有
4
种变量可以作为
wrap
的参数:
String
对象,创建的
CharBuffer
对象是只读的;
char[]
数组对象;
StringBuilder
对象;
StringBuffer
对象
·
hasArray()
P342
判断缓冲区是否从数据对象创建
·
array()
P342
如果缓冲区是从数组创建的,那么返回该数组的引用,否则抛出
UnsportedOperationException
异常
·
mark()
P343
将缓冲区的当前位置进行标记,视图缓冲区与创建它的缓冲区的标记是独立的
·
reset()
P343
将缓冲区的当前位置重置到标记处
·
put() putXXX()
P344
将数据传入缓冲区
,
在自定义的位置传入数据
,
缓冲区的位置不会自动变化
,
需要根据传入的数据类型手工设置
由于视图缓冲区的位置与基础缓冲区的位置是相互独立的,因此在使用视图缓冲区访问元素后,必须手工设置基础缓冲区的位置
ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //
缓冲区大小是否可以预先确定?
CharBuffer charBuffer = byteBuffer.asCharBuffer();
charBuffer.put("Hello");
/*
或者使用:
charBuffer.put(0, 'H'); charBuffer.position(charBuffer.position() + 1);
charBuffer.put(1, 'e'); charBuffer.position(charBuffer.position() + 1);
charBuffer.put(2, 'l'); charBuffer.position(charBuffer.position() + 1);
charBuffer.put(3, 'l'); charBuffer.position(charBuffer.position() + 1);
charBuffer.put(4, 'o'); charBuffer.position(charBuffer.position() + 1);
*/
byteBuffer.position(byteBuffer.position + Character.SIZE / 8 * charBuffer.position()); //
每个
char
占用
2
个字节
byteBuffer.putDouble(1.23);
·
flip()
P346
通常在将缓冲区中数据写入到文件之前使用,它将缓冲区的边界设置为当前位置,当前位置设置为
0
·
clear()
P347
将缓冲区的当前位置设置为
0
,边界设置为容量值
·
rewind()
P347
将缓冲区的当前位置设置为
0
·
compact()
P347
将缓冲区中当前位置和边界之间的元素复制到缓冲区开头,并把当前位置设置到最后一个元素后面,边界设置成容量
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
写入文件
(
1
)写入源和目的
从缓冲区当前位置开始,到边界为止,将其中的元素写入到文件中,并且从文件的当前位置开始写入
(
2
)通道对象的方法
·
write()
写入缓冲区中可访问的元素,文件位置自动增长。而另一种在文件制定的位置写入缓冲区中可访问元素的重载方法,文件当前位置不变
·
force()
在调用
write()
方法后,数据可能还未被写入到基础设备中,调用
force()
方法将保证数据写入到本地存储设备中,但不能保证数据写入到网络存储设备中
·
position()
获取、指定文件当前位置
·
close()
关闭通道
·
size()
获取文件中的字节数
·
trnsferTo()
写入到另一个通道
·
transferFrom()
从另一个通道读取
·
read(ByteBuffer buf, long position)
·
write(ByteBuffer buf, long position)
用于随机读写文件,完成后通道位置(也就是文件指针)不变
(
3
)写入代码
String phrase = "Hello";
File aField = new File(dirname, filename);
FileOutputStream file = new FileOutputStream(aFile, true);
FileChannel outChannel = file.getChannel();
byte[] bytes = phrase.getBytes();
buf.put(bytes);
buf.flip();
outChannel.write(buf);
file.close(); //
同样会关闭
outChannel
(
4
)集中写操作
将多个缓冲区中数据依次写入文件,调用
write(ByteBuffer[] buffers)
方法
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
11
章
读文件
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
FileInputStream
(
1
)构造函数
构造函数会验证文件是否存在,不存在则抛出异常
三种形参:文件路径名、
File
对象、
FileDescriptor
对象
(
2
)
read()
方法
使用
read()
方法将数据从文件读入缓冲区,文件位置将自动递增。从文件读入缓冲区的数据量取决于缓冲区的位置和边界
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
对一个文件同时进行读写
对同一个文件穿件
FileInputStream
和
FileOutputStream
,然后分别创建通道进行读写
使用
RandomAccessFile.getFilePointer()
获取文件指针与
FileChannel.getPosition()
获取通道位置是相同的
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
从标准输入流获取读取器
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in))
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
12
章
对象的序列化
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
序列化定义
P405
在外部文件中存储和获取对象的过程称之为序列化(
serialization
)。将对象写入文件称为对象序列化(
serializing an object
),而从文件读取对象称为将对象逆序列化(
deserializing
)。序列化包括将对象以及它们所包含的成员域写入流,但不涉及类的
static
成员。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
将对象写入文件
P408
File f = new File("MyFile");
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(myObject);
oos.close();
fos.close();
为了提高效率使用
ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
将对象序列化的条件
P408
对象所属类必须为
public
类型,必须实现
Serializable
接口。如果这个类的超类不可序列化,那么当这些超类有
public
类型的默认构造函数,且本类负责将不可序列化的超类的成员域序列化及逆序列化,那么本类也是可以序列化的。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
将基本数据类型写入对象流
P409
ObjectOutputStream
除了定义了将对象写入流的
writeObject()
方法外,还定义了将基本类型数据写入流的方法,如
writeInt()
、
writeChar()
等,此外还有与之相对应的读取方法,如
readInt()
、
readChar()
。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
transient
型数据成员
P413
对于不可序列化或者不希望序列化的成员域,可以将其定义为
transient
型,当对象逆序列化时,这样的成员域会被正确创建,其值为
null
。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6
|
从文件读取对象
P413
File f = new File("MyFile");
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
myObject = ois.readObject();
ois.close();
fis.close();
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
自定义序列化
P420
将类声明为
public
类型,并实现
Serializable
接口,重写
private void readObject(ObjectInputStream in) throws IOException
和
private void writeObject(ObjectOutputStream out) throws IOException, ClassNotFoundException
方法。一般来说先使用
in.defaultReadObject()
和
out.defaultWriteObject()
方法进行默认序列化操作,然后再自行处理需要的序列化、反序列化操作。
此外,可以通过在类中实现
Externalizable
接口来完全控制序列化过程。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8
|
将对象的变体写入对象流
P423
试图将同一个对象的多个变体(通过修改对象的成员域来形成多个变体)写入对象流,将会重复写入对象的第一个变体,如
String str;
str = "Str1"; out.writeObject(str);
str = "Str2"; out.writeObject(str);
str = "Str3"; out.writeObject(str);
这样实际上会重复写入对象
"Str1"
。采用
reset()
方法可以避免这个问题,如
String str;
str = "Str1"; out.reset(); out.writeObject(str);
str = "Str2"; out.reset(); out.writeObject(str);
str = "Str3"; out.reset(); out.writeObject(str);
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
13
章
泛型类
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
泛型定义
P425
泛型,又称参数化类型,是含有单个或多个类型参数的类或接口的定义。
<>
中的参数称为类型参数,泛型的类型实参只能是类或接口,而不能是基本数据类型,如果需要的话,使用他们的包装类
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
最左限制
P431
当提供类型实参后,泛型类将重新生成。编译器将使用
Object
类型替换类型变量的类型,因为
Object
是所有类的最终超类,所以
Object
类型是任何类的默认最左限制,最左限制取决于类型参数限制
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
相同的运行时类型
P434
同一个泛型的多个泛型类(给泛型提供不同类型的类型参数),它们的实例有相同的运行时类型,即范型本身
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
泛型类型参数的作用域
P435
泛型类型参数的作用域是除静态成员、静态方法、初始化器以外泛型类的全部定义。注意与泛化方法是不同的,这里讨论的是泛型类
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
泛型中的静态成员域
P435
尽管由泛型生成的新类型共享相同的运行时类型,但它们仍然拥有独立的静态成员域
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6
|
类型参数限制
P436
可以对类型实参进行一些约束,约束包括继承类、实现接口
public class MyType(T extends MyClass & Serializable & MyInterface>
{
}
如果不进行约束限制,则默认为
<T extends Object>
,这也就是
Object
作为默认最左限制的原因
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
泛型接口
·泛型可以实现一个或多个接口(包括泛型接口)。要求类型参数本身实现制定的接口,而不是继承它超类对该接口的实现,这就是内建限制
·典型任务:使泛型容器类使用
collection-based for
循环
条件:实现接口
Iterable<>
(实现该接口中的方法
iterator()
),然而方法
iterator()
的返回值类型
Iterator<T>
也是泛型接口,因此这个返回值类型要实现
Iterator<T>
接口中定义的所有方法,如:
import java.util.Iterator;
public class LinkedList<T> implements Iterable<t>
{
public Iterator<T> iterator()
{
return new ListIterator();
}
private class ListIterator implements Iterator<T>
{
public ListIterator() {...}
public boolean hasNext() {...}
public T next() {...}
public void remove() {...}
}
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8
|
原生类型
P452
将泛型类的泛型参数“去掉”后的类型称为原生类型。“去掉”是指将类型变量使用相应类型参数的最左限制替换,这个过程称为类型擦除,可以修改类型参数限制来控制最左限制
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9
|
通配符
P452
·实现描述
?
为通配符,它表示任何类或接口。如果方法代码不依赖于类型实参,可以使用通配符描述类型参数
·约束
通配符可以有两种限定约束
上界:
<? extends T>
,表示
T
以及
T
的之类可作为类型参数
下界:
<? super T>
,表示
T
以及
T
的超类可作为类型参数
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
10
|
Class
类
P457
Class
类不是普通的类,他被定义为泛型。对于一般的类而言,类型本身就是泛型
Class<>
的类型实参,如
Class<String>
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11
|
数组和泛型
P 458
数组元素不予许是由泛型生成的具体类型,只能使用无界限的通配符创建泛型数组,且泛型数组允许数组元素是相同泛型的多个泛型类实例,如
Vector<?>[] list = {
new
Vector<String>(),
new
Vector<Integer>()};
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
12
|
参数化方法
P460
含有一个或多个独立的类型参数的方法,称为参数化方法或泛化方法。类型参数可以增加约束,并且构造函数也可以作为泛化方法。如
public
static
<T> T createInstance(Class<T> cls)
,是方法的独立类型参数。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
13
|
参数化类型和继承
P466
可以将类定义为泛型类型实例的之类,方法和成员域可以从基类继承,但要注意,当派生类中的方法需要覆盖超类中方法时,采用一般的方法将没有效果,因为编译器用不同的记号将方法进行编译处理,所以基类中的方法不会被覆盖,为了达到覆盖的目的,编译器将采用桥接方法,将对继承的方法的任何调用转换为对派生类中定义的方法的调用,这个过程时隐式进行的。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
14
章
集合框架
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
集合类型
P469
·集:集中的对象没有排序方式,只是简单的把对象添加到集中,集中的对象不能有重复
·序列:线型方式存储,有开头和结尾。
java
序列划分为列表和队列两种,列表包括向量、链表、栈
·映射:存储
<
键
,
值
>
对,键用来标识对象,通过散列法确定值的存储位置
Java
对象集合指对象引用的集合,即集合只存储引用,而对象本身存储在集合之外
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
迭代器
P471
·枚举器
java.util.Enumeration<>
比标准迭代器少声明了一个方法
remove()
·迭代器
java.util.Iterator<>
声明方法
T next(); boolean hasNext(); void remove();
每次遍历集合后都需要重新获取迭代器,因为迭代器是单向、一次性的
·列表迭代器
java.util.ListIterator<>
比标准迭代器多声明了向前或向后遍历对象集合的方法
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
集合类
P475
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
集合接口
P476
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
向量
Vector
(
1
)构造函数
P478
向量的工作方是和数组类似
,但它能自动增大容量。默认的初始容量是
10
个对象,当容量不足时,容量将扩充一倍。这个默认设置有时并不适用,因此构造函数的重载方法中允许定义初始容量和增量值。需要注意的时,向量中存储的元素实际是对象的引用,也就是
int
型变量,而不是对象本身,其它的容器类也是一样的存储方式。向量中元素是连续存储的,在内存中是一整块,当容量改变时,需要将向量中的内容复制到新的内存空间,这个过程会消耗一定时间
(
2
)方法
ensureCapacity()
确保容量
setSize()
、
trimToSize()
改变容量
set()
改变元素
listIterator()
使用
ListIterator
迭代器遍历
toArray()
以数组形式返回向量中元素
(
3
)应用
集合中元素的排序。
java.util.Collections
定义有方法
sort()
实现
List<>
接口集合类中元素的排序,前提是集合中的元素实现了
Comparable<>
接口,即实现了
int compareTo()
方法
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6
|
栈
Stack
派生自
Vector
int search(Object obj)
返回值是基于
1
的索引。
java.util.Collection.shuffle(java.util.List<>)
将
List<>
接口的集合中的内容搅乱顺序。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
HashMap
映射
(
1
)机制
P496
映射
map
是一种数据存储方式,以这种方式存储可以最小化获取对象时所需的搜索代价。在
java
的集合框架中,由
HashMap<>
类实现的映射设置了一个用于成对存储键和对象的数组,用于存储键
/
值对的项称为桶。这个数组的索引是由键对象生成,方法是用该键对象的散列码计算存放键
/
对象对的数组偏移量,在默认情况下,这个操作由作为对象的
hashCode()
方法完成。虽然每个键各不相同,但并非每个键生成的散列码是唯一的,当两个或多个不同的键生成相同的散列码时,这种情况被称为冲突,
HashMap<>
对象的冲突处理方式是将所有散列码相同的键
/
对象存入同一个链表中,如果冲突频繁发生,会降低数据的存取速度。
Object
类定义的
hashCode()
方法利用对象的存储地址产生散列码,所以不同的对象总是有不同的散列码。从某种意义上这么做很好,因为可能每个键生成的散列码越不同,三列映射的操作就越有效。缺点上含有相同数据的不同对象将得到不同的散列码,这样就无法比较他们了。
(
2
)用自己创建的类的对象做键
两种方式:
覆盖
Object
类的
equals()
方法,比较两个不同的对象,但他们含有相同的数据,应该返回
true
。
覆盖
Object
类的
hashCode()
方法,应该使得方法产生的散列码在取值范围内均匀分布,且键值唯一。可以使用每个数据成员对应的整数值乘以不同的素数,然后求和作为散列码。
(
3
)
HashMap
的构造函数
可以指定初始容量和填充因子,填充因子值当散列表的长度达到填充因子和容量乘积的时候,容量将自动扩充为原来的两倍加一,容量默认为
16
,填充因子默认为
0.75
。
(
4
)
.get(K key)
如果实参键值不存在或者存储的对象为空,都返回
null
。
(
5
)处理映射中的所有元素,
3
种方法
·
.keySet()
返回所有键的
Set<K>
对象
Set<K> keys = map.keySet();
for(K key : keys) {...}
·
.values()
返回所有对象的
Collection<V>
对象
Collection<V> values = map.values();
for(V value : values) {...}
·
.entrySet()
返回所有键
/
对象对的
Set<Map.Entry<K, V>>
对象,每一对都是
Map.Entry<K, V>
类型的对象
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
15
章
实用类的集合
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
数组工具方法
java.util.Arrays
(
1
)填充数组
P511
void Arrays.fill(type[] array, type value)
除了可以填充基本数据类型数组,还可以填充对象数组,但在填充时,填充的是对象的引用,也就是说所有数组元素都引用同一个对象。
(
2
)比较数组
P512
boolean equals(type[] array1, type[] array2)
包含数据组元素数目相同且所有对应元素的值相等,返回
true
。元素的比较通过调用类的
equals()
方法判断的。
(
3
)对数组排序
P513
void sort(type[] array)
将数组元素进行升序排序
<T> void sort(T[] array, Comparator<? super T> comparator)
实用
comparator
比较器对数组元素进行排序,实现比较器接口
Comparator<>
的类可以是:
public
class
CompareElement<Element>
implements
Comparator<Element>
{
public
int
compare(Element e1, Element e2)
{
if
(e1 > e2)
return
1;
else
if
(e1 < e2)
return
-1;
else
return
0;
}
public
boolean
equals(Object comparator)
{
/*
*
实参comparator与当前比较器排序方式相同返回true
*
例如:
*/
if
(
this
== comparator)
return
true
;
if
(comparator ==
null
)
return
false
;
return
getClass() == comparator.getClass();
}
}
(
4
)搜索数组
P516
int binraySearch(type[] array, type value)
实用二分法在已经升序排序的数组中查找指定元素,找到返回索引值,否则返回一个负数
<T> int binraySearch(T[] array, type value, Comparator<? super T> comarator)
与上一个方法不同之处在于,该方法正确工作的前提是数组使用比较器
comparator
经过了排序
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
Observable
和
Observer
对象
P519
(
1
)当文档对象发生改变的时候,它的所有视图都需要被告知一种更改已经发生,因为他们需要更新显示的内容。文档是可观察的
Observable
,而视图是观察者
Observer
,这样就使得视图可以响应文档发生的变化。文档
-
视图结构描绘的是一个多对多关系,一个文档可能会有多个视图,一个视图可以观察多份文档。
(
2
)
Observable
是类,而
Observer
是接口,需要实现他的
update()
方法
/*
*
文档(可观察)
*/
public
class
Document
extends
Observable
{
private
Object
data
;
public
void
setData(Object data)
{
this
.
data
= data;
//
设置当前对象已经发生变化
this
.setChanged();
//
如果当前对象设置为已改变,则通知所有观察者,调用观察者的update()方法
this
.notifyObservers();
}
public
Object getData()
{
return
data
;
}
}
/**
*
视图(观察者)
*
@author
lnj
*
*/
public
class
View
implements
Observer
{
/**
*
必须实现必须实现update方法
*
observable
-
发生改变的Observable对象
*
arg
-
附加信息
*/
public
void
update(Observable observable, Object arg)
{
if
(observable
instanceof
Document)
System.
out
.println(
this
.toString() +
"
发现变化:"
+ ((Document)observable).getData());
}
}
public
void
reg()
{
Document doc =
new
Document();
View view1 =
new
View();
View view2 =
new
View();
//
将观察者进行注册
doc.addObserver(view1);
doc.addObserver(view2);
doc.setData(
"
下雨啦"
);
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
产生随机数
P523
(
1
)构造函数
Random r1 = new Random();
使用当前时钟作为随机数的种子。
Random r2 = new Random();
使用长整型数值作为种子值。
使用相同的种子创建的
Random
对象总会产生相同的序列。
(
2
)方法
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
时期和时间
P525
(
1
)
Date
日期时间对象,精确到毫秒
·解释
Date
对象
java.text.DateFormat
中定义了
4
种日期、时间格式:
SHORT
、
MEDIUM
、
LONG
、
FULL
java.util.Locale
中定义了国家、地区、语言信息
DateFormat
中定义了静态方法获取
DateFormat
对象:
getTimeInstance()
获取时间格式
getDateInstance()
获取日期格式
getDateTimeInstance()
获取日期时间格式
·解析日期时间字符串
parse()
(
2
)
GregorianCalendar
公历
P530
GregorianCalendar calendar = new GregorianCalendar();
.set()
设置日期和时间
.clear()
所有字段清零
.get()
获取字段值
.add() .roll()
增加或减小字段值
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
正则表达式
P535
(
1
)正则表达式功能通过
java.util.regex
包中的两个类实现,
Pattern
类,封装了正则表达式对象,
Matcher
封装了状态机的对象
(
2
)创建模式
Pattern
Pattern pattern = Pattern.compile("
正则表达式字符串
");
Pattern pattern = Pattern.compile("
正则表达式字符串
",
标志位
);
标志位来自
Pattern
中的常量字段
(
3
)创建
Matcher
对象
Matcher matcher = pattern.matcher("
待搜索字符串
");
matcher.reset("
改变待搜索的字符串
");
matcher.reset();
重置搜索结果索引
matcher.find()
搜索模式下一次的出现位置,通过
matcher.start()
和
matcher.end()
可以获取模式出现位置的索引值,也可以使用
matcher.group()
获取匹配的字符串
matcher.matches()
整个字符串与模式匹配时返回
true
(
4
)字符集
(
5
)查找和替换
String str =
"<td>A</td><td>B</td>"
;
String regEx =
"<td>"
;
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
//
存放替换后的新字符串
StringBuffer sb =
new
StringBuffer();
while
(m.find())
{
//
将找到的模式之前的字符串追加到sb中
m.appendReplacement(sb,
"<td nowrap>"
);
}
//
将剩余的字符追加到sb中
m.appendTail(sb);
//
此时sb为<td nowrap>A</td><td nowrap>B</td>
(
6
)捕获组
Matcher
对象的
group()
方法获得与正则表达式所定义的整个模式相匹配的子列,整个模式表示的内容被称为捕获组(
capturing group
)。除了整个表达式所定义的组之外,正则表达式中的每对括号都定义了一个独立的捕获组。整个正则表达式的捕获组编号为
0
,其他组编号按从正则表达式的左边开始计算开放圆括号的个数来进行。如:
(
7
)重排捕获组顺序
matcher.appendReplacement("
新字符串
", "
替换成字符串
");
其中的
"
替换成字符串
"
可以引用捕获组文本,方法是使用“
$
捕获组编号”,如
matcher.appendReplacement(newCode, "$1//($8, $2//)");
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
扫描器Scanner P552
java.util.Scanner
类定义了一个对象,该对象使用正则表达式扫描来自各种输入源的字符输入,并把输入表示为由各种基本类型组成的标记序列或者字符串。默认情况下,Scanner对象使用空白进行分割,空白字符是使Character类的isWhitespace()方法返回true的任意字符。使用scanner对象的userDelimiter()方法可以设置分隔符。
String
str =
"windowsXP windows2000 windows2003 windowsVista"
;
Scanner scanner =
null
;
//
使用默认的空白分隔符进行分割
scanner =
new
Scanner(str);
while
(scanner.hasNext())
System.
out
.println(scanner.next());
//
使用默认的空白分隔符,查找有名字的windows(非数字)
scanner =
new
Scanner(str);
Pattern pattern = Pattern.compile(
"//w*[^0-9]"
);
while
(scanner.hasNext())
{
if
(scanner.hasNext(pattern))
System.
out
.println(
"
找到"
+ scanner.next(pattern));
else
System.
out
.println(
"
跳过"
+ scanner.next());
}
//
使用新的分隔符(windows或者空格)
scanner =
new
Scanner(str);
scanner.useDelimiter(
"windows| "
);
while
(scanner.hasNext())
System.
out
.println(scanner.next());
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第16章
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
创建线程 P562
(1)将线程定义为Thread类的子类,并提供run()方法来取代继承的run()方法。
public
class
MyThread
extends
Thread
{
public
void
run()
{
try
{
while
(
true
)
{
System.
out
.println(
"I am running"
);
sleep(1000);
}
}
catch
(InterruptedException e)
{
System.
err
.println(
"InterruptedException"
);
}
}
public
static
void
main(String[] args)
{
Thread t =
new
MyThread();
t.start();
}
}
(2)使线程类实现Runnable接口,实现void run()方法。
public
class
MyThread1
implements
Runnable
{
public
void
run()
{
try
{
while
(
true
)
{
System.
out
.println(
"I am running"
);
Thread.sleep(1000);
}
}
catch
(InterruptedException e)
{
System.
err
.println(
"InterruptedException"
);
}
}
public
static
void
main(String[] args)
{
Thread t =
new
Thread(
new
MyThread1());
t.start();
}
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
线程方法 P564
(1)守护线程
守护线程是一个后台线程,它从属于创建它的线程,当创建守护线程的线程结束时,守护线程也随之结束。守护线程使用Thread对象的setDaemon(true)进行设置。非守护线程称为用户线程,它将拥有自己的生命周期,不依赖于创建它的线程,创建它的线程结束后,它仍然继续运行,用户线程使用Thread对象的setDaemon(false)设置。
(2)停止线程
Thread
对象的interpt()方法将向线程发送一个停止的信号,这样在线程执行sleep()方法时将引发InterruptedException异常,程序捕获这个异常即可中止线程。isInterrupted()检测线程是否已经发送停止信号。
(3)连接线程
thread1.join()
表示在当前线程中等待thread1线程结束,等待过程中可能发生InterruptedException。
(4)线程调度
当调用线程的sleep()方法时,即使没有其他线程在等待,该线程也至少会停止实参指定的一段时间,而调用yield()方法时,如果没有其他线程在等待,当前线程马上重新开始执行。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
线程同步 P570
(1)同步方法
public
synchronized
void
syncMethod()
{
}
确保在一个对象的所有同步方法中,一次只能有一个可以执行,不能保证一个类的多个对象同步方法互斥执行。
(2)静态同步方法
public static
synchronized
void
syncMethod()
{
}
确保一个类的所有静态同步方法中,一次只能有一个可以执行,是类范围的同步。
(3)同步代码块
synchronized
(theObject)
{
//
语句块
}
theObject
对象的同步语句块执行时,同一theObject对象的其他同步代码块或同步方法就不能执行。
(4)wait()、notify()、notifyAll()
只有在同步方法或者同步代码块中才能调用这3个方法。
wait()
挂起当前线程,直到调用了wait()方法所属于的那个对象的notify()或notifyAll()方法,调用wait()方法后,会释放当前对象的同步锁,这样该对象的其他同步方法或同步代码块才得以执行,该对象的notify()或notifyAll()方法才可能被调用。
notify()
重新启动一个线程,该线程调用了notify()方法所属的那个对象的wait()方法。
notifyAll()
使调用了wait()方法的所有线程都需重新启动,而wait()方法和notifyAll()方法属于同一个对象。
自悟:wait()、notify()、notifyAll()都是针对同一个对象不同线程而言的,而这个对象是一个“互斥资源”
public
class
Counter
{
private
int
m_CurrentNum
;
private
int
m_MaxNum
;
public
Counter()
{
m_CurrentNum
= 0;
m_MaxNum
= 0;
}
synchronized
public
void
increase()
{
while
(
m_CurrentNum
>=
m_MaxNum
)
{
try
{
Log.info(
"
数量饱和,请等待"
);
wait();
}
catch
(InterruptedException e)
{
Log.info(
"
等待过程中发生异常,该异常将被忽略"
);
Log.info(e.toString());
}
}
m_CurrentNum
++;
notifyAll();
Log.info(
"
数量增加,当前数量为"
+
m_CurrentNum
);
}
synchronized
public
void
decrease()
{
m_CurrentNum
--;
notifyAll();
Log.info(
"
数量减少,当前数量为"
+
m_CurrentNum
);
}
/**
*
获取当前计数
*
@return
*/
synchronized
public
int
getCurrentNum()
{
return
m_CurrentNum
;
}
/**
*
获取最大计数
*
@return
*/
synchronized
public
int
getMaxNum()
{
return
m_MaxNum
;
}
/**
*
设置当前计数
*
@param
num
*/
synchronized
public
void
setCurrentNum(
int
num)
{
m_CurrentNum
= num;
}
/**
*
设置最大计数
*
@param
num
*/
synchronized
public
void
setMaxNum(
int
num)
{
m_MaxNum
= num;
}
}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
包装非同步集合类 P591
java.util.Collections
类提供了从非同步的对象创建同步集、列表和映射的方法。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第22章 Java与XML
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
XML
Extensible Markup Language
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
XML
文档结构 P873
序言Prolog
XML
声明 XML declaration
文档类型声明 Document type declaration
文档体 Document body
XML
声明:
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
standalone
=
"yes"
?>
文档类型声明:
<!
DOCTYPE
rootElem
SYSTEM
"proverb.dtd"
>
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
预定义实体 P875
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
元素命名 P877
以字母或下划线开始,名字中可以使用数字.-。XML是区分大小写的,但忽略空白字符。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
通用实体general entity P877
<!ENTITY
copyright "(c) 2006 devtemptation">
定义copyright实体,它代表字符串“(c) 2006 devtemptation”。
<!ENTITY
doc SYSTEM "http://www.devtemptation.org/doc.txt">
定义doc实体,他代表http://www.devtemptation.org/doc.txt中的内容。
©right;
引用实体
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6
|
CDATA
段 P878
CDATA
段用来嵌入不希望XML处理器解析的数据,可以是二进制数据,CDATA段格式为
<![CDATA[
内容
]]>
。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
元素常规和属性常规(element-normal & attribute-normal)P879
元素常规:所有数据都是元素
属性常规:所有数据都被定义为属性值
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8
|
文档类型定义
文档类型定义(Document Type Definition DTD)定义了如何为特定类型的文档构造有效的元素
(1)声明DTD P881
XML 1.0
版本的文档只能有一个DOCTYPE声明。在声明中显示地包含文档中使用元素的标记声明称为内部子集(internal subset),而通过指定标识文档DTD的URI称为外部子集(external subset)。
<!
DOCTYPE
文档根元素名
SYSTEM
"URI"
>
外部子集,"URI"被称为系统标识符System ID。
<!
DOCTYPE
文档根元素名
PUBLIC
"URI"
>
外部子集,"URI"被称为公有标识符Public ID。
<!
DOCTYPE
文档根元素名
[<!ELEMENT
文档根元素(#PCDATA)
>]
>
内部子集
(2)定义元素 P883
<!ELEMENT
address (buildingnumber, street, city, state, zip)>
元素address可以按序出现元素buildingnumber、street、city、state、zip。
<!ELEMENT
buildingnumber (#PCDATA)>
元素buildingnumber只能含有可解析字符数据
<!ELEMENT
buildingnumber (#PCDATA|suite)*>
元素buildingnumber可以含有可解析字符数据或suite子元素,并且他们可以出现0次或多次,但不能限制他们的出现顺序。
<!ELEMENT
address (buildingnumber?, street, city, state, zip?)>
元素address含有的子元素中,buildingnumber和zip可选。
<!ELEMENT
address ((buildingnumber|buildingname))>
元素address必须且只含有子元素buildingnumber或buildername之一。
<!ELEMENT
address ((buildingnumber|buildingname)+)>
元素address必须至少含有一个子元素buildingnumber或buildername。
<!ELEMENT
address ((buildingnumber|buildingname)?)>
元素address含有一个子元素buildingnumber或一个子元素buildername或不含子元素。
<!ELEMENT
address ((buildingnumber|buildingname)*)>
元素address可以含有子元素buildingnumber或子元素buildername或两种子元素或不含子元素。
<!ELEMENT
zip EMPTY>
元素zip不能含有任何子元素和可解析字符数据。
+
至少出现一次;* 出现零次或多次;? 出现零次或一次;| 有左操作数或右操作数,但不能同时出现。
(3)定义元素属性 P885
<!ATTLIST
属性名 值类型 属性是否强制出现或默认值
>
<!ATTLIST
address
name
CDATA #REQUIRED
country CDATA #IMPLIED
level CDATA
"unknown"
area (
small|medium|large)
#REQUIRED
iscapital CDATA #FIXED
"no"
>
元素address必须具有属性name和area,属性country可选,level属性默认为unknown,area属性取值为small、medium、large三者之一,iscapital属性默认且只能为no。
(4)定义参数实体parameter entity P887
参数实体通过名字来表示一块解析文本,可以将这块文本插入DTD中不同的位置。参数实体只能用于DTD中,而通用实体用于文档中。
定义参数实体
<!ENTITY
% coordinates "X CDATA #REQUIRED
Y CDATA #REQUIRED"
>
引用参数实体
<!ATTLIST
address
name
CDATA #REQUIRED
country CDATA #IMPLIED
level CDATA
"unknown"
area (
small|medium|large)
#REQUIRED
iscapital CDATA #FIXED
"no"
%coordinates;
>
(5)更多属性值类型 P887
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9
|
构造良好文档的规则P891
如果在序言中出现XML声明,那么它必须包含XML的版本信息。XML文档的其他规范必须按照规定的顺序出现,字符编码后是standalone规范。
如果在序言中出现文档定义类型,那么DOCTYPE的名字必须与根元素的名字相一致,而且DTD中的标记声明必须符合书写标记声明的规则。
文档必须至少包含一个元素,即根元素,它包含其他所有元素,而且根元素的实例不能出现在另一个元素的文档中。所有元素必须嵌套正确。
文档体中的元素必须和DOCTYPE声明中标记的标记声明相一致。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
10
|
XM
名字空间
(1)解决多份XML文档组合成一个XML文档时发生的元素名冲突的问题。XML名字空间对标记中使用的名字进行限定,将同样的名字放在不同的名字空间中,就可以在不同标记中重复使用它们。从概念上讲,每个名字都是由包含它的名字空间的唯一URI进行限定,在实际使用中,通过名字空间前缀(namespace prefix)进行名字限定,名字空间的作用域是在其中声明名字空间的元素内容,和该元素的所有子元素。
(2)
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
standalone
=
"no"
?>
<
sketcher:sketch
xmlns:sketcher
=
"http://www.devtemptation.org/dtds/sketches"
>
<
sketcher:circle
radius
=
"15"
angle
=
"0"
>
<
sketcher:color
R
=
"150"
G
=
"250"
B
=
"100"
/>
<
sketcher:position
x
=
"30"
y
=
"40"
/>
</
sketcher:circle
>
</
sketcher:sketch
>
在元素sketch上定义名字空间,前缀为sketcher,URI为http://www.devtemptation.org/dtds/sketches。并对元素名sketch、circle、color、position进行限定。
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
standalone
=
"no"
?>
<
sketch
xmlns
=
"http://www.devtemptation.org/dtds/sketches"
>
<
circle
radius
=
"15"
angle
=
"0"
>
<
color
R
=
"150"
G
=
"250"
B
=
"100"
/>
<
position
x
=
"30"
y
=
"40"
/>
</
circle
>
</
sketch
>
使用默认名字空间,可以不加限定名而使用这个名字空间的元素名和属性名,他们都隐式的存在于这个名字空间中。
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
standalone
=
"no"
?>
<
sketch
xmlns
=
"http://www.devtemptation.org/dtds/sketches"
xmlns:print
=
"http://www.devtemptation.org/dtds/printed"
>
<
circle
radius
=
"15"
angle
=
"0"
>
<
color
R
=
"150"
G
=
"250"
B
=
"100"
/>
<
position
x
=
"30"
y
=
"40"
/>
</
circle
>
<
print:circle
print:lineweight
=
"3"
print:linestyle
=
"dashed"
/>
</
sketch
>
可以在单个元素中声明若干个名字空间,如使用一个默认名字空间和另一个名字空间
(3)DTD并没有为名字空间提供支持,因此要保持文档有效,必须在DTD中考虑名字空间前缀和声明名字空间元素的xmlns属性。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11
|
XML
模式
(1)定义 P893
为描述XML文档的结构,W3C开发了XML模式,它和DTD起着同样的作用,但它比DTD提供了更多的功能,如数据类型和格式,因此使用XML模式更好,XML模式语言也被称为XSD(XML Schema Definition)。XSD本身也是XML文档,它是用来描述XML文档结构的XML文档。在XML模式中,声明(declaration)指定作为文档文本的元素;定义(definition)定义元素类型。
(2)定义模式 P894
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
schema
xmlns
=
"http://www.w3.org/2001/XMLSchema"
>
<
element
name
=
"address"
type
=
"AddressType"
/>
<
complexType
name
=
"AddressType"
>
<
sequence
>
<
element
name
=
"buildingnumber"
type
=
"positiveInteger"
/>
<
element
name
=
"street"
type
=
"string"
/>
<
element
name
=
"city"
type
=
"string"
/>
<
element
name
=
"state"
type
=
"string"
/>
<
element
name
=
"zip"
type
=
"decimal"
/>
</
sequence
>
</
complexType
>
</
schema
>
模式必须有唯一的根元素schema,并且可以使用名字空间。模式文档拥有元素element、complexType、schmea等元素,element元素可以有属性name和type。它定义了实例文档根元素为address,它有子元素buildingnumber、street、city、state、zip且子元素必须按顺序出现。
(3)定义元素P895
复杂元素:包括子元素或属性,使用complexType定义,简单元素:不含子元素或属性,只含数据(标准类型数据或自定义类型数据),使用simpleType定义。
<
element
name
=
"city"
元素名称
type
=
"string"
元素数据类型
minOccurs
=
"1"
元素最少出现次数,默认为1
maxOccurs
=
"1"
元素最多出现次数,默认为1
default
=
"
北京"
默认值
fixed
=
"
北京"
/>
固定元素值
(4)定义复杂元素属性P896
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
xsd:schema
xmlns:xsd
=
"http://www.w3.org/2001/XMLSchema"
>
<
xsd:element
name
=
"circle"
type
=
"circleType"
></
xsd:element
>
<
xsd:complexType
name
=
"circleType"
>
圆的元素类型
<
xsd:attribute
name
=
"x"
type
=
"xsd:double"
use
=
"required"
/>
属性x、y必须,且为double类型
<
xsd:attribute
name
=
"y"
type
=
"xsd:double"
use
=
"required"
/>
<
xsd:attribute
name
=
"radius"
use
=
"required"
>
属性radius必须
<
xsd:simpleType
>
<
xsd:restriction
base
=
"xsd:double"
>
为double类型,比0大
<
xsd:minExclusive
value
=
"0"
/>
</
xsd:restriction
>
</
xsd:simpleType
>
</
xsd:attribute
>
<
xsd:attribute
name
=
"color"
use
=
"required"
>
属性color必须
<
xsd:simpleType
>
<
xsd:restriction
base
=
"xsd:string"
>
为string类型且来自枚举值red、blue
<
xsd:enumeration
value
=
"red"
/>
<
xsd:enumeration
value
=
"blue"
/>
</
xsd:restriction
>
</
xsd:simpleType
>
</
xsd:attribute
>
</
xsd:complexType
>
</
xsd:schema
>
(5)属性组 P897
若干不同元素具有相同的属性组,为避免重复定义,可以使用属性组。
定义属性组coords,它由两个元素组成。
<
attributeGroup
name
=
"coords"
>
<
attribute
name
=
"x"
type
=
"double"
use
=
"required"
/>
<
attribute
name
=
"y"
type
=
"double"
use
=
"required"
/>
</
attributeGroup
>
使用属性组定义点的元素类型
<
complexType
name
=
"PointType"
>
<
attributeGroup
ref
=
"coords"
/>
</
complexType
>
(6)定义备选元素
<
complexType
name
=
"sketchType"
>
<
choice
minOccurs
=
"0"
maxOccurs
=
"unbounded"
>
<
element
name
=
"line"
type
=
"LineType" /
>
<
element
name
=
"rectangle"
type
=
"RectangleType" /
>
<
element
name
=
"circle"
type
=
"CircleType" /
>
</
choice
>
</
complexType
>
定义SketchType类型元素,包含0个或更多个子元素,且每个子元素都是LineType、RectangleType、CircleType类型其中之一。
(7)使用XML模式 P903
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
circle
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation
=
"root.xsd"
>
</
circle
>
表示该实例文档名字空间为http://www.w3.org/2001/XMLSchema-instance,且前缀为xsi,名字空间xsi中的属性noNamespaceSchemaLocation是文档的模式所在的路径。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
12
|
使用XML文档编程P904
SAX
:用于XML解析的简单API(Simple API for XML)
使用基于事件的处理来阅读XML文档,它由回调机制实现,SAX是快速、储存效率高的、有选择处理XML文档内容的方法。
javax.xml.parsers.SAXParserFactory SAX
工厂
javax.xml.parsers.SAXParser SAX
解析器
DOM
:XML的文档对象模型(Document Object Model)
解析XML文档时,整个文档都在内存中形成,作为封装好的Document类型对象返回给应用程序,缺点是占用内存较大。
javax.xml.parsers.DocumentBuilderFactory DOM
工厂
javax.xml.parsers.DocumentBuilder Dom
解析器
这4个类都是抽象类,JAXP被设计为允许插入不同解析器及它们的工厂类,DOM和SAX解析器都是独立于JDK开发的,他们可以随着发展集成新的解析器。随J2SE5发布的是Apache的Xerces解析器,J2SE5支持DOM3rd、SAX2.0.2和XLST1.0。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
13
|
使用SAX P906
(1)
//
创建SAX解析器工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
System.
out
.println(
"SAXParserFactory:/t"
+ spf.toString());
//
将解析器设置为可识别名字空间,这样解析器将能获取每个元素和属性的uri和localName,否则只能将元素名和属性名作为单独的名字报告。
spf.setNamespaceAware(
true
);
//
验证DTD、XSD及文档体内容与DTD、XSD中的定义是否一致
spf.setValidating(
true
);
//
创建解析器
SAXParser parser = spf.newSAXParser();
System.
out
.println(
"SAXParser:/t"
+ parser.toString());
File f =
new
File(filename);
//
声明自定义的XML解析器实践处理器
DefaultHandler dh =
new
MySAXHandler();
parser.parse(f, dh);
public
class
MySAXHandler
extends
DefaultHandler
{
//
通过继承DefaultHandler类,覆盖掉其中的无为方法,从而实现SAX解析事件的处理。覆盖startDocument()、endDocument()、startElement()、endElement()等方法解析xml文档;覆盖warning()、error()、fatalError()方法捕获解析XML过程中出现的警告、错误、致命错误。
}
如果XML文档没有DTD定义,那么解析器将无法区分可忽略空白字符,从而将它们当作字符数据处理。
可以处理带有名字空间的文档,并且可以使用限定名,但若要处理名字空间前缀,需要打开“报告名字空间前缀”特征。
(2)使用不同的解析器P909
可以使用不同的SAX解析器,只需将该解析器的jar文件加入到-classpath中。
(3)解析器的特征和特性P909
特定的解析器有自己的特征和特性,从而来控制和报告XML文档的处理。
使用SAXParserFactory对象的getFeature()、setFeature()访问特性;SAXParser对象的getProperty()、setProperty()访问特性;XMLReader对象的getFeature()、setFeature()、getProperty()、setProperty()访问特征和特性。
(4)使用模式 P921
SchemaFactory
sf = SchemaFactory.newInstance(XMLConstants.
W3C_XML_SCHEMA_NS_URI
);
Schema schema = sf.newSchema(
new
File(
"root.xsd"
));
spf.setSchema(schema);
SchemaFactory.newInstance()
的实参指明了模式定义语言,常量javax.xml.XMLConstants.
W3C_XML_SCHEMA_NS_URI
为http://www.w3.org/2001/XMLSchema;SchemaFactory.newSchema()的实参指明了xsd文件对象。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第23章 创建和修改XML文档
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
设置DOM解析器
javax.xml.parsers.*
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory
对象常用方法:
DocumentBuilder builder = builderFactory.newDocument();
builder
对象常用方法:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
常用接口 P929
(1)org.w3c.dom.Node
它封装文档树中节点的对象类型,是XML文档组件对象的基础,它也是其他接口的超接口,它们是:Element元素、Attr元素属性、Text元素文本、CDATASection不解析字符数据、Comment注释、DocumentType文档类型、Document文档、DocumentFragment轻量级文档,封装文档的子树、Entiry实体、EntityReference实体引用、Notation记号、ProcessingInstruction预处理指令。
(2)Document
由DocumentBuilder的parse()方法返回,是文档的最顶层节点。
(3)NodeList
由Node对象的getChildNodes()方法返回。
(4)NamedNodeMap
由Node对象的getAttributes()方法返回。
(5)Attr
由Node对象getAttributes()方法得到的NamedNodeMap对象的item(int index)方法强制转换而来。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
处理可忽略空白字符和元素内容P935
某些元素含有多个#text元素,他们可能是元素内容或标记中可忽略的空白符。使用builderFactory对象的setIgnoringElementContentWhitespace(true)可避免将可忽略字符报告为一个节点。对于元素内容中产生的#text元素,可使用((Text)node).getWholeText()获取其内容。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
创建XML文档P939
可以使用Document doc = builder.newDocument();创建Document对象的引用,但这种方法有局限性,因为没有办法修改DocumentType节点来反映合适的DOCTYPE声明。使用下面的方法可以解决这个问题:
DOMImplementation domImpl = builder.getDOMImplementation();
DocumentType docType = domImpl.createDocumentType("
根元素限定名", "publicID", "systemID");
Document doc = domImpl.createDocument("
名字空间", "根元素名", docType);
填充文档。org.w3c.Document接口声明了向Document对象中添加节点的方法,可以创建节点来封装元素、属性、文字、实体引用、注释、CDATA段和预处理指令,调用Document对象的createXXX()方法。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
24
章
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
JDBC P967
建立在其他标准程序
——
数据库接口的基础上,这就是
X/Open SQL CLI(Call Level Interface
调用级接口
)
的技术规范。
这个库是在
java.sql
程序包中实现的,这是一个为访问多种数据库而提供统一
API
的类和接口的集合。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
数据库编目(
Catalog
)
P969
指数据库的系统表,系统标用于存储关于数据库、表以及标的组成的信息。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
元数据(
metadata
)
P969
描述数据库内容的数据成为元数据,或者数据字典(
data dictionary
)
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
带空格的列别名
P976
使用双引号引起来
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
JDBC
包
P978
JDBC
库被设计为执行
SQL
语句的接口,而不是进行数据库访问的高级抽象层。
JDBC
是通过实现针对每个特定数据库的
JDBC
接口,即驱动程序来实现对不同数据库的操作。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6
|
数据库驱动程
P980
(1)JDBC
驱动程序是由实现
Driver
接口的类定义的
(2)
系统属性
jdbc.drivers
定义了
JDBC
驱动程序,
DriverManager
类在装入系统的时候将尝试装入这个驱动程序
System.setProperty(jdbc.drivers, sun.jdbc.odbc.jdbcOdbcDriver;com.microsoft.sqlserver.jdbc);
因为安全策略的限制,在使用
setProperty()
时会抛出
SecurityException
异常
(3)
使用
Class.forName()
注册
调用
forName()
使得
java
解释器的类装入实参指出的驱动程序。当装入了这个驱动程序类之后,这个类装入器将判断这个驱动程序是否有
static
初始化代码,如果有,那么将在装入该类之后立即执行
static
初始化代码。这就是驱动程序类可以实例化自身,并且注册
DriverManager
对象创建实例的原因。此外,它还可以执行其他可能需要的初始化代码,例如该驱动程序使用本机的方法则要装入一个动态链接库,并且由于这些都是在这个类装入时发生的,因此可以保证这些处理都发生在调用其他驱动程序方法之前。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
使用
java.util.Properties
作为
DriverManager.getConnection(String url, Properties info)
的实参
P983
Properties prop = new Properties();
prop.setProperty(user, sa);
prop.setProperty(password, );
Connection conn = DriverManager.getConnection(sourceURL, prop);
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8
|
JDBC
驱动程序操作的日志记录
P983
DriverManager
的静态方法
public static void setLogWriter(PrintWriter out)
和
public static PrintWriter getLogWriter()
使用
DriverManager.setLogWriter(null);
取消日志记录
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9
|
登录超时设置
P983
DriverManager.setLoginTimeout(int secs)
和
DriverManager.getLoginTimeout()
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
10
|
JDBC
驱动的
4
种实现形式
(1)JDBC-ODBC
桥驱动程序
把
JDBC
方法翻译成
ODBC
函数调用实现,适用于没有
JDBC
驱动的情况下
(2)
本机
API/
部分
Java
驱动程序
通过本机方法访问数据库,需要调用厂商库
(3)
网络协议全部为
Java
客户
通过中间件通讯(通常是
TCP/IP
)把
JDBC
请求翻译成数据库访问的调用
(4)
本机协议全部为
Java
(如果可能的话,尽量使用该方式)
直接使用该服务器的本机协议于数据库服务器通信,没有把
Java
初始化请求转换成其他形式的翻译过程
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11
|
JDBC
驱动官方网址
http://servlet.java.sun.com/products/jdbc/drivers
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
12
|
DriverManager.getConnection()
的工作原理
当调用该方法时,会在
DriverManager
注册的驱动程序中迭代处理,并且依次询问每个驱动程序是否能够处理
URL
,第一个处理的驱动程序将创建一个
Connection
对象,然后将其返回给应用程序。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
13
|
获取
Driver
对象
使用
DriverManager.getDriver(String url)
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
14
|
批处理执行
SQL
语句
需要批处理执行的
SQL
语句依次使用
addBatch()
方法,
executeBatch()
用于执行,
clearBatch()
方法清除用过的批处理语句
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
15
|
ResultSet
的一些特殊
get
方法
getDate()
返回
java.sql.Date
getTime()
返回
java.sql.Time
getTimestamp()
返回
java.sql.Timestamp
getAsciiStream()
返回
java.io.InputStream
,用于
SQL
的
LONGVARCHAR
类型
大多数基本数据访问方法都能很灵活的从
sql
数据类型转换成
java
数据类型,比如任何
sql
数据都可以用
getString()
来读取
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
16
|
ResultSetMetaData
使用
rs.getMetaData()
来获取,而不需要
rs.next()
方法。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
第
25
章
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1
|
SQL-92
标准定义了一个数据类型集,但这个集与
java
中的数据类型并非一一对应
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2
|
约束结果集
statement.getMaxRows();statement.setMaxRows();
设置结果集最大行数,
0
表示没有限制。
statement.getMaxFieldSize();statement.setMaxFieldSize();
结果集任意字段的最大字节数,
0
表示没有限制。
statement.getQueryTimeout();statement.setQueryTimeout();
查询超时时间,
0
表示没有限制。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3
|
LONGVARCHAR
和
LONGVARBINARY
类型数据的处理
设置:
setAsciiStream()
、
setUnicodeStream()
、
setBinaryStream()
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4
|
检测空值
从
ResultSet
中获取数据后调用
wasNull()
方法
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5
|
特殊数据类型
java.sql.Date
,定义了
ResultSet.getDate()
返回值类型,继承
java.util.Date
java.sql.Time
,定义了
ResultSet.getTime()
返回值类型,继承
java.util.Date
java.sql.Timestamp
,定义了
ResultSet.getTimestamp()
返回值类型,继承
java.util.Date
java.math.BigDecimal
,定义了任意精度的十进制数,
java.math.BigInteger
和
java.math.BigDecimal
运算速度慢
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6
|
流的处理
P1028
LONGVARCHAR getAsciiStream()
LONGVARCHAR getCharacterStream()
LONGVARBINARY getBinaryStream()
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7
|
调用存储过程
P1030
通过
java.sql.CallabelStatement
接口提供功能
调用字符串
{? = call procedureName(?, ?)}
使用
setXXX()
方法提供输入参数值
使用
registerOutParameter(index, type)
注册输出参数
使用
getXXX()
方法获取输出参数值
返回值也是一种输出参数
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8
|
SQL Exception
(1)
三种基本信息
异常消息
getMessage()
SQL
状态
getSQLState()
厂商错误编码
getErrorCode()
(2)
异常链
·抛出的异常可能会形成一个链,特定的
SQL Exception
是链上的一个结点
·显示链上全部异常
catch(SQLException e)
{
do
{
//
输出异常信息
}while((e = e.getNextException()) != null);
}
·把自定义的异常加入到链上的第一个结点前
catch(SQLException e)
{
//
自定义异常
SQLException e1 = new SQLException(message, sqlState, errorCode);
e1.setNextException(e);
throw e1;
}
·把自定义的异常加入到链上的最后一个结点之后
catch(SQLException e)
{
//
找到链上的最后一个结点
SQLException lastE = e;
while(lastE.getNextException() != null)
lastE = lastE.getNextException();
//
将异常加入到链上的最后一个结点之后
SQLException e1 = new SQLException(message, sqlState, errorCode);
lastE.setNextException(e1);
throw e;
}
·我认为应该把自定义的异常加入到链上的第一个结点前,这样就能形成一个异常链,这个链越在后的结点,对应的异常就越底层
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9
|
SQLWarning
派生自
SQLException
,同样有三种“基本信息”和“链”
必须显示请求
getWarning()
方法获得警告信息
Connection
、
Statement
、
ResultSet
接口都定义了
getWarning()
方法
|