java源码阅读专栏说明
1、源码阅读不包括异常和错误
2、一篇或者几篇文章是说不清楚的。光看博客也不会有多大的进步,或者说过段时间就会忘记。java源码阅读专栏旨在根据 代码 和文档的基础上来记录一些我自己的感受和想法。当然,我也会汲取一些其他人的收获。并将它们传播。
3、最主要的是了解这些源码的编程风格和一些规范,具体的一些说明,这个接口或者类是干什么的?可能也会涉及到
接下来开始,第一个包的了解:
java.io包是继承和接口运用得最棒例子了(这话是听别人说的,可从这个包的结构,可以看出确实很流畅。),我也是初次来阅读它,确实,io在平时用的也很多。而且io里面的东西也是其他部分的一些基础。所以我准备先来看看这个包的一些东西。
文章目录
概览图
字节流可以处理所有类型数据,如:图片,MP3,AVI视频文件,而字符流只能处理字符数据。只有是处理纯文本数据,就要优先考虑使用字符流,除此之外都用字节流。
Interfaces部分
更多其他,请参考我的另一篇博客:Java基础总结!精华版!
的第19点。
接口实际上是定义了一种规范,所有实现了相应接口的类,或者接口,都得去安照它规范去做一些开发。
Closeable
Closeable使用,其中有一个方法,close(),这个接口还有一个父接口AutoCloseable,autocloseable来自java.lang
可以看到close方法抛出的是io异常,查看后发现,InputStream,OutputStream都实现了Closeable接口。
说明,Closeable就是用来定义关闭流的一个“规范”(接口就是一种规范)。
DataInput && DataOutput
DataInput提供从二进制流读取字节,并从其中重建任何Java原语类型的数据。 同时还提供根据 UTF-8 修改版格式的数据重构 String 的工具。
DataOutput和它相反,提供将数据从任何Java基本类型转换为一系列字节,并将这些字节写入二进制流。同时还提供了一个将 String 转换成 UTF-8 修改版格式并写入所得到的系列字节的工具。
这个两个接口中有很多的方法,具体的我也不照搬文档了,但我发现,所有的接口,都是没有访问修饰符的,即 public…,因为接口中默认的,所以的方法都是公有的,且没有方法体的。
平时的开发写代码的时候,可以模仿。还有每一个方法都有对应的注释,注释也符合java的一些规范,比如最起码的,方法描述,参数介绍,返回值…
ObjectInput &ObjectOutput
如上,ObjectInput和ObjectOutput继承了两个接口。
在ObjectInput和ObjectOutput中的方法,都用了访问修饰符。作者和版本如下。。作者是佚名,jdk中有很多的代码作者,都是佚名。
Serializable
Serializable接口,只是一个标记接口,就是说,它没有方法和属性。
更多关于序列化,请查看我的另一篇博客:
深入【Java】底层细节知识点 的第十七点
java.io中Externalizable接口就继承了serializable接口
Flushable
Flushable 是可刷新数据的目标地。调用 flush 方法将所有已缓冲输出写入底层流。
该接口定义了一个我们常用的方法,flush(),通过将所有已缓冲输出写入底层流来刷新此流。
还有其他的一些接口,比如: ObjectInputValidation, FileFilter ,FilenameFilter , ObjectStreamConstants
Classes部分
首先,输入流,输出流是相对内存而言的。内存在一定程度上可以理解为,程序,即你写的代码;但是代码运行其实是在内存中的。这一块,jvm会进行进一步研究。
字节流:
输入流:相对于内存,向内存中写入;
输出流:相对于内存,从内存往外读;
字符流:
Reader(字符输入流),我是这样理解的,从文件(文本)中读取一些字符,然读取到内存中;
Writer(字符输出流),从内存中拿到东西写到文件中;
类这部分,我们就按照这幅图来研究,
InputStream
此抽象类是表示字节输入流的所有类的超类。
InputStream 是一个抽象类。
类中,有两个非抽象的方法:
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
/**
这两个方法本身没有什么特别,特别之处,在于,没有直接用下面的方法,
而是包了一层(上面的方法)
这种,大家也都清楚,两个方法,方法名相同,参数个数或者类型不同,
叫做方法重载。
重载的好处:便于记忆筛选,体现了java的多态
*/
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
接下来,看我的一个例子,这样写起来,确实清晰明了。
public void test(int i){
//做些什么
}
public void test(int[] intArr){
//像这样做点什么
test(intArr[i]);
}
public void test(int[][] intArr){
test(intArr[i][j]);
}
再比如我项目中的一个例子:
byte[] data = null;
try {
InputStream in = bi2is(bi);
//数据在底层传输的时候,是要拆分成包,帧的
//在进行网络操作时往往出错,因为你调用available()方法时,对发发送的数据可能还没有到达,你得到的count是0。
int count = 0;
while (count == 0){
count = in.available()
}
data = new byte[count];
in.read(data);
in.close();
// 对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
String s = encoder.encode(data);// 返回Base64编码过的字节数组字符串
// s=s.substring(0,10);
return s;
} catch (IOException e) {
e.printStackTrace();
}
return "";
我们只需关注 in.read(data);
这行,来理解输入流中的read方法。
in中存了一些东西,我们用read方法,读出来,然后做一些处理
OutputStream
对称的总是美好的~
此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。
Reader
Reader是抽象类并且有俩抽象方法(read(char[], int, int) 和 close()),所以,子类都必须重写这俩方法,但一般的子类都会自定义这俩方法。
java中的字符是Unicode编码的,是双字节的。InputStream是用来处理字节的,在处理字符文本时很不方便。Java为字符文本的输入提供了专门的一套类Reader。Reader类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。
现在是不是有一个困惑:字节和字符的区别?
字节(Byte)是一种计量单位,表示数据量多少,它是计算机信息技术用于计量存储容量的一种计量单位。
字符是指计算机中使用的文字和符号,比如1、2、3、A、B、C、~!·#¥%……—*()-+、等等。
两者不是一个位面的东西。没有可比性。
另外:不同编码里,字符和字节的对应关系不同:
-
ASCII码中:一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。
一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制。最小值0,最大值255。 -
UTF-8编码中:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。
-
Unicode编码中:一个英文字符等于两个字节,一个中文(含繁体)等于两个字节。
符号:英文标点占一个字节;中文标点占两个字节。
举例:英文句号“.”占1个字节的大小;中文句号“。”占2个字节的大小。 -
UTF-16编码中:一个英文字母字符或一个汉字字符存储都需要2个字节(Unicode扩展区的一些汉字存储需要4个字节)。
-
UTF-32编码中:世界上任何字符的存储都需要4个字节。
Writer
写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()
流的使用,结束以后,一定要关闭;
1、jdk1.7之前
InputStream is = null;
try {
//使用流
}finally {
if(is!=null){
is.close();//抛出异常
}
}
2、
try-with-resource(jdk1.7以后)
try(InputStream is = null;) {
//使用流
}