JDK源码阅读(1)_简介+ java.io
1.简介 针对这一个版块,主要做一个java8的源码阅读笔记。会对一些在javaWeb中应用比较广泛的java包进行精读,附上注释。对于容易混淆的知识点给出相应的对比分析。
精读的源码顺序主要如下: (1)第一部分:这部分是java开发的最常见包和类,要求精读:
- java.io
- java.lang
- java.util
(2)第二部分:这一部分是java web开发的核心内容之一,要求要有深刻的理解。(包括了java的反射、网络io、非阻塞、并发编程)————某些大牛说,这一部分运用的好坏,掌握的水平高低,会决定一个java开发程员的档次:
- java.lang.reflect
- java.net
- javax.net.*
- java.nio
- java.util.concurrent.*
(3)第三部分:这一部分要求不高,进行简单泛读,能看懂、会用即可:
- java,lang.annotation
- javax.annotation
- java.lang.ref
- java.math
- java.rmi.*
- javax.rmi.*
- java.security.*
- javax.security.*
- java.sql
- javax.sql.*
- javax.transaction.*
- java.test
- java.xml.*
- org.w3c.dom.*
- org.xml.sax.*
- javax.crypto.*
- javax.imageio.*
- javax.jws.*
- java.util.jar
- java.util.logging
- java.util.prefs
- java.util.regex
- java.util.zip
2.源码阅读:—— day1:(java.io_BufferedInputStream类) (1)java.io——BufferedInputStream类
package java.io;
// java.io包,通过数据流、序列化和文件系统提供系统输入和输出
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
// 导入一个包,这个包运用到了一个多线程的原子更新器 public class BufferedInputStream extends FilterInputStream {
// 继承fileinputstream,为输入流添加一些功能;使用他防止每次读取时都得进行实际写操作;代表“使用缓冲区”
private static int DEFAULT_BUFFER_SIZE = 8192;
// 该变量定义了默认的缓冲大小 为8192;
private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
// 最大长度依然是Integer.MAX_VALUE,并不是Integer.MAX_VALUE-8 protected volatile byte buf[];
// 存储数据的内部缓冲区数组,必要的时候可以用另外一个大小不同的数组替换它;
// 注意volatile关键字表示不稳定变量,每次线程存取都应该直接从主程序中读取
// (作用于多线程环境中)防止主程序值改变,影响其中某个线程的值无法匹配对应而出错;
private static final
AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
AtomicReferenceFieldUpdater.newUpdater
(BufferedInputStream.class, byte[].class, "buf");
// 缓存数组的一个原子更新器,该成员变量与buf数组的volatile关键字一起,实现buf数组的原子的更新;
protected int count;
// 比缓冲区中最后一个有效字节的索引大 1 的索引。此值始终处于0
到buf.length
的范围内;
// 从buf[0]
到buf[count-1]
的元素包含从底层输入流中获取的缓冲输入数据。 protected int pos;
// pos = position ,缓冲区中的当前位置,这是将从buf数组中读取的下一个字符的索引;
// 此值始终处于0
到count
的范围内。如果此值小于count
,则buf[pos]
将作为下一个输入字节;
// 如果此值等于count
,则下一次read
或skip
操作需要从包含的输入流中读取更多的字节。
protected int markpos = -1;
// 最后一次调用mark
方法时pos
字段的值为 -1; markpos的值始终处于-1
到pos
的范围内,
// 如果输入流中没有被标记的位置,则此字段为-1;如果输入流中有被标记的位置,则
protected int marklimit;buf[markpos]
将用作reset
// 操作后的第一个输入字节。如果markpos
不是-1
,则从位置buf[markpos]
到buf[pos-1]
之间的
//所有字节
都必须保留在缓冲区数组中
(尽管对count
、pos
和markpos
的值进行适当调整后,这些字节可能移动到
//缓冲区数组中的其他位置);
除非pos
与markpos
的差超过marklimit
,否则不能将其丢弃。
// 调用mark
方法后,在后续调用reset
方法失败之前所允许的最大提前读取量。
// 只要pos
与markpos
之差超过marklimit
,就可以通过将markpos
设置为-1
来删除该标记。 private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}
// 如果输入流为 null ,则抛出传输流关闭“stream closed”的异常
// 如果输入流不为 null ,则返回输入流,并将数据存储于 input 中 private byte[] getBufIfOpen() throws IOException {
byte[] buffer = buf;
if (buffer == null)
throw new IOException("Stream closed");
return buffer;
}
// 创建一个输入流数组,用来保存其参数;当输入保存的参数数组为 null 时,抛出“stream closed”异常,
// 当不为 null 时,直接返回数组 buffer ,并把输入流存储在数组之中; public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE); // java中,用this引用当前对象;
}
// 创建一个缓冲输入流 BufferedInputStream 并保存其数据,即输入流 in ,以便将来使用;
// 回调缓冲输入流,并且保存其默认参数(缓冲输入流的长度); public BufferedInputStream(InputStream in, int size) {
super(in); // java类中使用super引用父类成分,InputStream是BufferedInputSream的父类;
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0"); buf = new byte[size];
}
// 创建具有指定缓冲区大小的BufferedInputStream
并保存其参数,即输入流in
,
// 以便将来使用。创建一个长度为size
的内部缓冲区数组并将其存储在buf
中。 private void fill() throws IOException {
byte[] buffer = getBufIfOpen();
if (markpos < 0)
pos = 0; // 没有标记,总是指向缓冲流的初始位置;
else if (pos >= buffer.length) // 位置比缓冲区长度大,缓冲区中没有空间了;
if (markpos > 0) { // 抛出缓冲区的前半部分;
int sz = pos - markpos; // 字符串数据的长度;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0; // 进行复制和初始化 pos 和 markpos;
} else if (buffer.length >= marklimit) {
markpos = -1; // 缓冲区太大了,是一个无效的标志位,返回-1;
pos = 0; // 降低缓冲区的内容;
} else if (buffer.length >= MAX_BUFFER_SIZE) {
throw new OutOfMemoryError("Required array size too large");
} else { // 缓冲区进行拓展
int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
pos * 2 : MAX_BUFFER_SIZE;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
// 如果这里是不同步的关闭,则不能进行替换;
// 注意:如果满了则需要进行拓展变换
// 对于多线程来说,永远不能达到
// 唯一的方式是通过关闭来结束
// 插入 buf == null;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos; // 数量
} public synchronized int read() throws IOException {
if (pos >= count) {
fill(); // 如果位置的值 pos 大于等于 长度数量 count;则调用fill()方法
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
} // 将字符串读入到数组 array 之中,如果需要,最多进行 1 次;
private int read1(byte[] b, int off, int len) throws IOException {
int avail = count - pos;
if (avail <= 0) {
// 如果请求的长度至少和缓冲器一样的大,并且没有进行 mark/reset 操作;
// 不要急于拷贝不要急于拷贝字节到本地缓冲器之中,如果这样,缓冲流将会无害级联;
if (len >= getBufIfOpen().length && markpos < 0) {
return getInIfOpen().read(b, off, len);
}
fill();
avail = count - pos;
if (avail <= 0) return -1;
}
int cnt = (avail < len) ? avail : len;
System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
pos += cnt;
return cnt;
} // 以所给的偏移量开始,从输入字节流中,读取到具体字节流数组中;
public synchronized int read(byte b[], int off, int len)
throws IOException
{
getBufIfOpen(); // 检查缓冲流是否关闭;
if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
} int n = 0;
for (;;) {
int nread = read1(b, off + n, len - n); // 读入
if (nread <= 0)
return (n == 0) ? nread : n; // 简单的一个选择语句,当n==0返回nread,否则返回n;
n += nread;
if (n >= len)
return n;
// 如果输入流没有关闭,但是,已经没有字节可用,则直接返回;
InputStream input = in;
if (input != null && input.available() <= 0)
return n;
}
} public synchronized long skip(long n) throws IOException { // n为跳过字节数;
getBufIfOpen(); // 检查字符流是否关闭
if (n <= 0) {
return 0;
}
long avail = count - pos; //确定可用长度 if (avail <= 0) {
// 如果没有设定标志位置,也没有保存在 buffer 缓冲器中;
if (markpos <0)
return getInIfOpen().skip(n); // 填满 buffer 缓冲器,用以保存字节,等待重新设置;
fill();
avail = count - pos;
if (avail <= 0)
return 0;
} long skipped = (avail < n) ? avail : n; // 选择判断语句,跳过 avail 长度,或者跳过 n 长度;
pos += skipped;
return skipped;
} //返回可以从该输入流中读取(或跳过)的字节数的估计数,而不需要对该输入流的方法的下一次调用进行阻塞。
//下一个调用可能是同一个线程或另一个线程。此多字节的单个读或跳过不会阻塞,但可能读取或跳过更少字节。
public synchronized int available() throws IOException {
int n = count - pos;
int avail = getInIfOpen().available();
return n > (Integer.MAX_VALUE - avail)
? Integer.MAX_VALUE
: n + avail;
} public synchronized void mark(int readlimit) {
marklimit = readlimit;
markpos = pos;
} // reset()重置方法;
public synchronized void reset() throws IOException {
getBufIfOpen(); // 如果缓冲流关闭会抛出异常;
if (markpos < 0) // 标志位置小于 0 ,会抛出异常;
throw new IOException("Resetting to invalid mark");
pos = markpos;
} public boolean markSupported() {
return true; // 测试该输入流支持位置标志;
}
// 关闭此输入流并释放与流相关联的任何系统资源;
// 一旦流已经关闭,进一步read(),available(),reset(),或skip()调用会抛出IOException;
// 关闭先前关闭的流没有效果。
public void close() throws IOException {
byte[] buffer;
while ( (buffer = buf) != null) {
if (bufUpdater.compareAndSet(this, buffer, null)) {
InputStream input = in;
in = null;
if (input != null)
input.close();
return;
}
//其他的情况下,一个新的缓冲区被重新装入,调用fill()方法;
}
}
}
这一块儿还算比较简单,看看api也差不多,有时间还是应该看看源码,会知其所以然~
JDK源码阅读(1)_简介+ java.io的更多相关文章
- JDK源码阅读-------自学笔记(一)(java.lang.Object重写toString源码)
一.前景提要 Object类中定义有public String toString()方法,其返回值是 String 类型. 二.默认返回组成 类名+@+16进制的hashcode,当使用打印方法打印的 ...
- JDK源码阅读-DirectByteBuffer
本文转载自JDK源码阅读-DirectByteBuffer 导语 在文章JDK源码阅读-ByteBuffer中,我们学习了ByteBuffer的设计.但是他是一个抽象类,真正的实现分为两类:HeapB ...
- JDK源码阅读(三):ArraryList源码解析
今天来看一下ArrayList的源码 目录 介绍 继承结构 属性 构造方法 add方法 remove方法 修改方法 获取元素 size()方法 isEmpty方法 clear方法 循环数组 1.介绍 ...
- JDK源码阅读-FileInputStream
本文转载自JDK源码阅读-FileInputStream 导语 FileIntputStream用于打开一个文件并获取输入流. 打开文件 我们来看看FileIntputStream打开文件时,做了什么 ...
- JDK源码阅读(一):Object源码分析
最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 has ...
- 利用IDEA搭建JDK源码阅读环境
利用IDEA搭建JDK源码阅读环境 首先新建一个java基础项目 基础目录 source 源码 test 测试源码和入口 准备JDK源码 下图框起来的路径就是jdk的储存位置 打开jdk目录,找到sr ...
- JDK源码阅读-FileOutputStream
本文转载自JDK源码阅读-FileOutputStream 导语 FileOutputStream用户打开文件并获取输出流. 打开文件 public FileOutputStream(File fil ...
- JDK源码阅读-ByteBuffer
本文转载自JDK源码阅读-ByteBuffer 导语 Buffer是Java NIO中对于缓冲区的封装.在Java BIO中,所有的读写API,都是直接使用byte数组作为缓冲区的,简单直接.但是在J ...
- JDK源码阅读-RandomAccessFile
本文转载自JDK源码阅读-RandomAccessFile 导语 FileInputStream只能用于读取文件,FileOutputStream只能用于写入文件,而对于同时读取文件,并且需要随意移动 ...
- JDK源码阅读-FileDescriptor
本文转载自JDK源码阅读-FileDescriptor 导语 操作系统使用文件描述符来指代一个打开的文件,对文件的读写操作,都需要文件描述符作为参数.Java虽然在设计上使用了抽象程度更高的流来作为文 ...
随机推荐
- Java compareTo() 方法
以金钱实交(realPay),和使用预存(usePurseFee)为例: if ( realPay.compareTo(usePurseFee) <=0) { XXXXXXX; }else { ...
- alex python of day1
Print("hello word!")#打印hello word!向python世界发生第一声呐喊,仪式很重要 定义变量 name="Alex Li" nam ...
- canvas 粒子效果
var canvas = document.createElement('canvas'); var cxt = canvas.getContext('2d'); var W = canvas.wid ...
- 【转载】 Java:按值传递还是按引用传递详细解说
前天在做系统的时候被Java中参数传递问题卡了一下,回头查阅了相关的资料,对参数传递问题有了新的了解和掌握,但是有个问题感觉还是很模糊,就是Java中到底是否只存在值传递,因为在查阅资料时,经常看到有 ...
- SurfaceView 使用demo 飞机游戏小样
本demo 主要使用了surfaceview 画图. 1.在线程中对canvas操作. 2.实现画图 3.surfaceView 继承了view 可以重写ontouchevent方法来操作输入. 代码 ...
- 输入一个A和B,,A<=B,A>=1,B<=pow(10,18)计算F=B!/A!结果的最后一位
*************************************************************************代理运行函数,判断结果,进行输出*********** ...
- Swift Runtime ?
你肯定也想过 在OC中相信每一个iOS开发都知道Runtime, 现在Swift也更新到4.0版本了,要是你也学习过Swift的话你可能也会想过这样一个问题,OC大家都是到是有动态性的,你能通过run ...
- (译)ABP之依赖注入
原文地址:https://aspnetboilerplate.com/Pages/Documents/Dependency-Injection 什么是依赖注入 传统方式的问题 解决方案 构造函数注入 ...
- ASP.NET Core中的OWASP Top 10 十大风险-跨站点脚本攻击 (XSS)
不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: https://dotnetcoretutorials.com/201 ...
- C++课程设计2
PS:大一下学期C++课程设计 1.成绩管理系统 #include<stdio.h> #include<string> #include<iostream> #in ...