从今天开始简单开始读一遍jdk的源码,估计这个时间会很长,慢慢啃吧。。。。(首先说一句抱歉,因为很多图都是直接百度扣的,图太多了不能为每一个图附上原版链接,不好意思!)

  在网上看了很多的教程,读源码有一定的顺序,按照包的顺序:java.lang包,java.util包,java.util.concurrent包,java.util.concurrent.atomic包,java.lang.reflect包,java.lang.annotation包,java.util.concurrent.locks包,java.io包,java.nio包,java.sql包,java.net包;

  大概数了一下,有11个包,暂时就把这11个包读完应该就差不多了,应该可以对jdk源码会理解很多,而且中间可能会涉及到一些其他的知识,我也是新手,也顺便学一下;

  当然也不可能把所有的方法都慢慢的去分析、去读,重点看一些比较重要的方法看看,很多的重载方法和不常用的方法可以选择性的省略。。。适合自己的才是最好的!比如一个方法基本上都用不到的,我们就简单瞄两眼就可以了,用的频繁的方法可以去看看实现原理。

1.概述

  对于java.lang包我们可以说是用得很多了,但是一直没有系统的整理一下,比如一个很熟悉的类Object,如果让你说说这个类中有哪些方法啊?(亲身遇到的一个面试题。。。)

  先看看这个包下常用都有些什么类吧,借来的一个图,1优先级最高,4优先级最低

1) Object 1
2) String 1
3) AbstractStringBuilder 1
4) StringBuffer 1
5) StringBuilder 1
6) Boolean 2
7) Byte 2
8) Double 2
9) Float 2
10) Integer 2
11) Long 2
12) Short 2
13) Thread 2
14) ThreadLocal 2
15) Enum 3
16) Throwable 3
17) Error 3
18) Exception 3
19) Class 4
20) ClassLoader 4
21) Compiler 4
22) System 4
23) Package 4
24) Void 4

  下面这个更全面,描述了java.lang包下的类主要是负责哪些方面的;

2.Object类

  对于这个类很熟悉吧,所有的类默认都是继承这个类;

//任何类默认都会继承这个类
public class Object {
//这个方法顾名思义,就是将一些native方法注册一下,可以简单理解成每一个native方法都连接着一个C/C++的具体实现
private static native void registerNatives(); //此处的代码块静态会调用上面的这个native方法
//所谓的native方法,就是底层用C/C++实现的,java可以有办法去调用这些其他语言的方法,可以了解一下JNI
static {
registerNatives();
} //这也是一个native方法,就是获取一个类的字节码文件
public final native Class<?> getClass(); //获取一个类的hash值,简单说说哈希值,这个在map中用的比较多;其实任意对象----->通过一个hash函数计算------>得到一个很大的数字(这就是hashCode)---
//---->这个hashCode进行取余计算等方式,就得到数组的下标;
public native int hashCode(); //可以看到这里比较的就是两个对象的引用,换句话说就是看看两个对象是不是同一个对象
public boolean equals(Object obj) {
return (this == obj);
} //克隆,想想现实中的克隆人。。。这里就是克隆一个和原来对象一模一样的对象
//注意,克隆分为浅克隆和深度克隆,深度克隆就是克隆出来的对象和原对象无关了,而浅克隆就是和原先对象有点关系,具体的什么关系呢?
//我简单说说浅克隆,原先对象中保存了一个Person实例的引用,而克隆的对象中也保存的是同一个Person的引用,当在克隆对象中对这个引用进行修改,原对象也会牵连。。。
protected native Object clone() throws CloneNotSupportedException; //这个方法就是将当前类基本信息以字符串形式打印出来,一般就是类名+@+hashCode变为16进制
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
} //多线程中用于随机唤醒一个线程的方法,这两个notify方法都要和wait方法一起用
public final native void notify(); //唤醒所有线程
public final native void notifyAll(); //让一个线程休息一下一定时间,这个方法会释放当前的锁,想了解的可以看看我以前的博客,或者自己看看资料
//注意wait方法和sleep方法的区别
public final native void wait(long timeout) throws InterruptedException; public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
} if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
} if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
timeout++;
} wait(timeout);
} //这个0可不是等待0秒啊,是等待无限长的时间,直到被唤醒
public final void wait() throws InterruptedException {
wait(0);
} //这个方法看看就好, 最没用的方法;主要用于jvm的垃圾回收,即使调用这个方法但是不保证一定立即进行回收。。。
protected void finalize() throws Throwable { }
}

3.String类

  关于这个类用得很多,初学的时候最多的就是比较String,StringBuffer,StringBulider。。。我就把常用的那些方法给说一下,很少用的方法选择性的删除

package java.lang;

import sun.misc.FloatingDecimal;
import java.util.Arrays; abstract class AbstractStringBuilder implements Appendable, CharSequence {
//看来这个StringBuilder本质上也是一个字节数组,和String不同的是这里没有被final修饰
char[] value; //字符数组的容量
int count; AbstractStringBuilder() {
} //根据传进来的参数确定字符数组的大小
AbstractStringBuilder(int capacity) {
value = new char[capacity];
} //返回字符数组中实际数据的数量
public int length() {
return count;
} //返回字符数组的最大容量
public int capacity() {
return value.length;
} //一下三个方法都是确保那个字符数组大小足够而进行的扩容操作;首先判断你要确保新字节数组多大,
//如果新数组容量比原来数组大,那么就进行扩容,扩容的时候还需要进行判断,比较系统自动扩容之后
//的容量和你所确保的容量做个对比,如果系统扩容还达不到你的要求,那么新字节数组的大小就用你确保的那个容量吧
//最后就是将原来数组中的数据复制到新的数组中
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
} private void ensureCapacityInternal(int minimumCapacity) { if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
} void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0)
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
} //去除数组中多余的位置;比如一个数组最大容量为5,但是实际放了3个数据,空出来两个位置,于是
//可以将对于的两个空位置去掉(其实就是将那是那三个数据复制到一个新的数组中,然后改变value引用)
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
} //设置字节数组的长度,多余的空位置添加'\0',这其实就是代表空字符,可以理解为null
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength); if (count < newLength) {
for (; count < newLength; count++)
value[count] = '\0';
} else {
count = newLength;
}
} //根据传进来的索引获取字节数组对应的数据
public char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
} //截取字节数组的连续的某几个字符,放到一个新的字节数组中
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
if (srcBegin < 0)
throw new StringIndexOutOfBoundsException(srcBegin);
if ((srcEnd < 0) || (srcEnd > count))
throw new StringIndexOutOfBoundsException(srcEnd);
if (srcBegin > srcEnd)
throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
} //将字符数组某个位置的字符覆盖
public void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
value[index] = ch;
} //传入一个对象,将这个对象转化为字符串,然后将该字符串(就是一个字符数组)添加到当前字符数组的末尾
//append方法就是在当前字符数组中后面添加所要添加的对象
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
} //首先要确保容量足够,再就是调用String类的getChars方法就是将传进去的str从0到最后,一次复制到value字节数组中
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
} //将StringBuffer类型的字符字符数组复制到本类的字符数组中(首先要保证容量足够)
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return append("null");
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
} //将一个字符数组的某一段复制到本类的字符数组当中
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0)
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
} //在当前字符数组中添加boolean字符
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
value[count++] = 't';
value[count++] = 'r';
value[count++] = 'u';
value[count++] = 'e';
} else {
ensureCapacityInternal(count + 5);
value[count++] = 'f';
value[count++] = 'a';
value[count++] = 'l';
value[count++] = 's';
value[count++] = 'e';
}
return this;
} //在当前字符数组最后中添加一个字符
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
} //在当前字符数组后面添加一个int类型(4个字节)的数据,要保证容量足够
//后面还有添加各种数据类型long,double,float等省略
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
count = spaceNeeded;
return this;
} //对一个字符数组中某一段进行删除,给出了起始位置和终点位置,可以看到就是利用的是数组的复制
//重点System.arraycopy方法,可惜这是一个native方法,看不到源码
public AbstractStringBuilder delete(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
end = count;
if (start > end)
throw new StringIndexOutOfBoundsException();
int len = end - start;
if (len > 0) {
System.arraycopy(value, start+len, value, start, count-end);
count -= len;
}
return this;
} //删除字符数组指定位置的字符
public AbstractStringBuilder deleteCharAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
System.arraycopy(value, index+1, value, index, count-index-1);
count--;
return this;
} //目的是为了让一个新的字符数组,代替本字符数组的某一段
//其实还是通过数组的复制
public AbstractStringBuilder replace(int start, int end, String str) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (start > count)
throw new StringIndexOutOfBoundsException("start > length()");
if (start > end)
throw new StringIndexOutOfBoundsException("start > end"); if (end > count)
end = count;
int len = str.length();
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount); System.arraycopy(value, end, value, start + len, count - end);
str.getChars(value, start);
count = newCount;
return this;
} //截取字符数组的某一段,其实就是新建了一个String类型的
public String substring(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
throw new StringIndexOutOfBoundsException(end);
if (start > end)
throw new StringIndexOutOfBoundsException(end - start);
return new String(value, start, end - start);
} //向StringBuilder中插入一个字节数组的某一段,省略好多的重载insert方法
public AbstractStringBuilder insert(int index, char[] str, int offset,
int len)
{
if ((index < 0) || (index > length()))
throw new StringIndexOutOfBoundsException(index);
if ((offset < 0) || (len < 0) || (offset > str.length - len))
throw new StringIndexOutOfBoundsException(
"offset " + offset + ", len " + len + ", str.length "
+ str.length);
ensureCapacityInternal(count + len);
System.arraycopy(value, index, value, index + len, count - index);
System.arraycopy(str, offset, value, index, len);
count += len;
return this;
} //从前往后查看某个字符串的位置
public int indexOf(String str) {
return indexOf(str, 0);
} //从前往后其实就是调用String的indexof方法
public int indexOf(String str, int fromIndex) {
return String.indexOf(value, 0, count,
str.toCharArray(), 0, str.length(), fromIndex);
} //从后往前找指定字符串的位置
public int lastIndexOf(String str, int fromIndex) {
return String.lastIndexOf(value, 0, count,
str.toCharArray(), 0, str.length(), fromIndex);
} //逆序字符数组,实现很简单,不要看hasSurrogate了,反正我是没看懂这个boolean的。。。
public AbstractStringBuilder reverse() {
boolean hasSurrogate = false;
int n = count - 1;
for (int j = (n-1) >> 1; j >= 0; --j) {
char temp = value[j];
char temp2 = value[n - j];
if (!hasSurrogate) {
hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
|| (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
}
value[j] = temp2;
value[n - j] = temp;
}
if (hasSurrogate) { for (int i = 0; i < count - 1; i++) {
char c2 = value[i];
if (Character.isLowSurrogate(c2)) {
char c1 = value[i + 1];
if (Character.isHighSurrogate(c1)) {
value[i++] = c1;
value[i] = c2;
}
}
}
}
return this;
} //留给子类实现,直接打印字符串
public abstract String toString(); //返回字符数组
final char[] getValue() {
return value;
} }

4.StringBuilder类

  有关于这个类其实很容易,就两层结构,final class StringBuilder extends AbstractStringBuilder,我们重点就在这个父类上,子类其实没做什么事,只是简单的调用了父类实现的那些方法而已。。。

  AbstractStringBuilder类:

package java.lang;

import sun.misc.FloatingDecimal;
import java.util.Arrays; abstract class AbstractStringBuilder implements Appendable, CharSequence {
//看来这个StringBuilder本质上也是一个字节数组,和String不同的是这里没有被final修饰
char[] value; //字符数组的容量
int count; AbstractStringBuilder() {
} //根据传进来的参数确定字符数组的大小
AbstractStringBuilder(int capacity) {
value = new char[capacity];
} //返回字符数组中实际数据的数量
public int length() {
return count;
} //返回字符数组的最大容量
public int capacity() {
return value.length;
} //一下三个方法都是确保那个字符数组大小足够而进行的扩容操作;首先判断你要确保新字节数组多大,
//如果新数组容量比原来数组大,那么就进行扩容,扩容的时候还需要进行判断,比较系统自动扩容之后
//的容量和你所确保的容量做个对比,如果系统扩容还达不到你的要求,那么新字节数组的大小就用你确保的那个容量吧
//最后就是将原来数组中的数据复制到新的数组中
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
} private void ensureCapacityInternal(int minimumCapacity) { if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
} void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0)
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
} //去除数组中多余的位置;比如一个数组最大容量为5,但是实际放了3个数据,空出来两个位置,于是
//可以将对于的两个空位置去掉(其实就是将那是那三个数据复制到一个新的数组中,然后改变value引用)
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
} //设置字节数组的长度,多余的空位置添加'\0',这其实就是代表空字符,可以理解为null
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength); if (count < newLength) {
for (; count < newLength; count++)
value[count] = '\0';
} else {
count = newLength;
}
} //根据传进来的索引获取字节数组对应的数据
public char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
} //截取字节数组的连续的某几个字符,放到一个新的字节数组中
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
if (srcBegin < 0)
throw new StringIndexOutOfBoundsException(srcBegin);
if ((srcEnd < 0) || (srcEnd > count))
throw new StringIndexOutOfBoundsException(srcEnd);
if (srcBegin > srcEnd)
throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
} //将字符数组某个位置的字符覆盖
public void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
value[index] = ch;
} //传入一个对象,将这个对象转化为字符串,然后将该字符串(就是一个字符数组)添加到当前字符数组的末尾
//append方法就是在当前字符数组中后面添加所要添加的对象
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
} //首先要确保容量足够,再就是调用String类的getChars方法就是将传进去的str从0到最后,一次复制到value字节数组中
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
} //将StringBuffer类型的字符字符数组复制到本类的字符数组中(首先要保证容量足够)
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return append("null");
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
} //将一个字符数组的某一段复制到本类的字符数组当中
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0)
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
} //在当前字符数组中添加boolean字符
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
value[count++] = 't';
value[count++] = 'r';
value[count++] = 'u';
value[count++] = 'e';
} else {
ensureCapacityInternal(count + 5);
value[count++] = 'f';
value[count++] = 'a';
value[count++] = 'l';
value[count++] = 's';
value[count++] = 'e';
}
return this;
} //在当前字符数组最后中添加一个字符
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
} //在当前字符数组后面添加一个int类型(4个字节)的数据,要保证容量足够
//后面还有添加各种数据类型long,double,float等省略
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
count = spaceNeeded;
return this;
} //对一个字符数组中某一段进行删除,给出了起始位置和终点位置,可以看到就是利用的是数组的复制
//重点System.arraycopy方法,可惜这是一个native方法,看不到源码
public AbstractStringBuilder delete(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
end = count;
if (start > end)
throw new StringIndexOutOfBoundsException();
int len = end - start;
if (len > 0) {
System.arraycopy(value, start+len, value, start, count-end);
count -= len;
}
return this;
} //删除字符数组指定位置的字符
public AbstractStringBuilder deleteCharAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
System.arraycopy(value, index+1, value, index, count-index-1);
count--;
return this;
} //目的是为了让一个新的字符数组,代替本字符数组的某一段
//其实还是通过数组的复制
public AbstractStringBuilder replace(int start, int end, String str) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (start > count)
throw new StringIndexOutOfBoundsException("start > length()");
if (start > end)
throw new StringIndexOutOfBoundsException("start > end"); if (end > count)
end = count;
int len = str.length();
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount); System.arraycopy(value, end, value, start + len, count - end);
str.getChars(value, start);
count = newCount;
return this;
} //截取字符数组的某一段,其实就是新建了一个String类型的
public String substring(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
throw new StringIndexOutOfBoundsException(end);
if (start > end)
throw new StringIndexOutOfBoundsException(end - start);
return new String(value, start, end - start);
} //向StringBuilder中插入一个字节数组的某一段,省略好多的重载insert方法
public AbstractStringBuilder insert(int index, char[] str, int offset,
int len)
{
if ((index < 0) || (index > length()))
throw new StringIndexOutOfBoundsException(index);
if ((offset < 0) || (len < 0) || (offset > str.length - len))
throw new StringIndexOutOfBoundsException(
"offset " + offset + ", len " + len + ", str.length "
+ str.length);
ensureCapacityInternal(count + len);
System.arraycopy(value, index, value, index + len, count - index);
System.arraycopy(str, offset, value, index, len);
count += len;
return this;
} //从前往后查看某个字符串的位置
public int indexOf(String str) {
return indexOf(str, 0);
} //从前往后其实就是调用String的indexof方法
public int indexOf(String str, int fromIndex) {
return String.indexOf(value, 0, count,
str.toCharArray(), 0, str.length(), fromIndex);
} //从后往前找指定字符串的位置
public int lastIndexOf(String str, int fromIndex) {
return String.lastIndexOf(value, 0, count,
str.toCharArray(), 0, str.length(), fromIndex);
} //逆序字符数组,实现很简单,不要看hasSurrogate了,反正我是没看懂这个boolean的。。。
public AbstractStringBuilder reverse() {
boolean hasSurrogate = false;
int n = count - 1;
for (int j = (n-1) >> 1; j >= 0; --j) {
char temp = value[j];
char temp2 = value[n - j];
if (!hasSurrogate) {
hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
|| (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
}
value[j] = temp2;
value[n - j] = temp;
}
if (hasSurrogate) { for (int i = 0; i < count - 1; i++) {
char c2 = value[i];
if (Character.isLowSurrogate(c2)) {
char c1 = value[i + 1];
if (Character.isHighSurrogate(c1)) {
value[i++] = c1;
value[i] = c2;
}
}
}
}
return this;
} //留给子类实现,直接打印字符串
public abstract String toString(); //返回字符数组
final char[] getValue() {
return value;
} }

  

  再看子类StringBuilder那就简单了:

package java.lang;

//我们将这个父类看了一遍这里就简单多了,因为基本的方法父类都已经实现了,这里就是简单调用一下
//我们就简单看看一些重要的方法
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
//初始化字符数组的大小
public StringBuilder() {
super(16);
} //也可以自定义字符数组的大小
public StringBuilder(int capacity) {
super(capacity);
} //初始化一个字符串的时候,我们会先创建一个比字符串大16的一个字符数组,然后将字符串添加进去
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
} //没有做什么事,就是简单的调用的一下父类的方法
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public StringBuilder append(String str) {
super.append(str);
return this;
} //扩展一以下,可以在后面添加StringBuilder类型的数据
private StringBuilder append(StringBuilder sb) {
if (sb == null)
return append("null");
int len = sb.length();
int newcount = count + len;
if (newcount > value.length)
expandCapacity(newcount);
sb.getChars(0, len, value, count);
count = newcount;
return this;
} //下面省略一堆append方法,就是简单的调用父类的append的各种重载方法
//还省略一些知识简单的调用父类方法的这种无聊的方法。。。 //实现父类的toString方法,返回一个字符串
public String toString() { return new String(value, 0, count);
} //下面这两个方法挺有意思的,这两个方法是本类独有的,可以传入io流,将数据写入到字节数组中或者从字节数组中读取数据
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeInt(count);
s.writeObject(value);
} private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
count = s.readInt();
value = (char[]) s.readObject();
} }

  

  有没有发现,StringBuilder类和String类一样是被final修饰了的,是属于不可变的,关于final关键字修饰的知识,大概提一下,不可变指的是引用不可变,内容可以变,例如下面代码:

StringBuilder name = new StringBuilder("java小新人");
final StringBuilder str = name; name.append("hello");
System.out.println(str); //java小新人hello str = "world";//这里编译器会报错

  随意提一下StringBuffer类,我们看看这个类:final class StringBuffer extends AbstractStringBuilder,居然也是继承了AbstractStringBuilder这个类,那么可以知道内部方法和StringBuilder一模一样,那么有什么区别呢?随便看一个StringBuffer中的简单的方法,如下所示;

  很清楚的看到有个synchronized关键字,这个关键字就涉及到多线程的时候,同一时刻只有一个线程能够访问这个方法,想详细了解synchronized关键字用法的可以看看我之前的博客,或者自己看看资料也行。。。

5.总结

  自己看看源码还是很有必要的,我总是感觉要行框架中走出来,基础始终都是基础,我们只有把基础搞的扎实了,学java就很容易了!

  也许我的这种看源码的方式不适合你,但是作为一个参考,你也可以自己去看看源码了,对了,当我们去复制一个java源码中的一个类的时候,会发现注释的代码很多,那有没有办法可以直接删除所有注释呢?找了好久找到了一个java小脚本,只需要修改一下目录名称就好了。。。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter; public class Delete { private static int count = 0; /**
* 删除文件中的各种注释,包含//、/* * /等
* @param charset 文件编码
* @param file 文件
*/
public static void clearComment(File file, String charset) {
try {
//递归处理文件夹
if (!file.exists()) {
return;
} if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
clearComment(f, charset); //递归调用
}
return;
} else if (!file.getName().endsWith(".java")) {
//非java文件直接返回
return;
}
System.out.println("-----开始处理文件:" + file.getAbsolutePath()); //根据对应的编码格式读取
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
StringBuffer content = new StringBuffer();
String tmp = null;
while ((tmp = reader.readLine()) != null) {
content.append(tmp);
content.append("\n");
}
String target = content.toString();
//String s = target.replaceAll("\\/\\/[^\\n]*|\\/\\*([^\\*^\\/]*|[\\*^\\/*]*|[^\\**\\/]*)*\\*\\/", ""); //本段正则摘自网上,有一种情况无法满足(/* ...**/),略作修改
String s = target.replaceAll("\\/\\/[^\\n]*|\\/\\*([^\\*^\\/]*|[\\*^\\/*]*|[^\\**\\/]*)*\\*+\\/", "");
//System.out.println(s);
//使用对应的编码格式输出
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset));
out.write(s);
out.flush();
out.close();
count++;
System.out.println("-----文件处理完成---" + count);
} catch (Exception e) {
e.printStackTrace();
}
} public static void clearComment(String filePath, String charset) {
clearComment(new File(filePath), charset);
} public static void clearComment(String filePath) {
clearComment(new File(filePath), "UTF-8");
} public static void clearComment(File file) {
clearComment(file, "UTF-8");
} public static void main(String[] args) {
clearComment("C:\\Users\\asus\\Desktop\\jdk源码文件\\03.java"); //删除目录下所有java文件注释
//删除某个具体文件的注释
//clearComment("D:\\proj\\scm\\action\\AbcdefgAction.java");
} }

  后续的还会慢慢的看jdk源码的,最好是一遍看的时候有的方法可以敲敲代码试试!

简单看看jdk7源码之java.lang包01的更多相关文章

  1. JDK1.8源码(二)——java.lang.Integer 类

    上一篇博客我们介绍了 java.lang 包下的 Object 类,那么本篇博客接着介绍该包下的另一个类 Integer.在前面 浅谈 Integer 类 博客中我们主要介绍了 Integer 类 和 ...

  2. JDK1.8源码(三)——java.lang.String 类

    String 类也是java.lang 包下的一个类,算是日常编码中最常用的一个类了,那么本篇博客就来详细的介绍 String 类. 1.String 类的定义 public final class ...

  3. JDK1.8源码(一)——java.lang.Object类

    本系列博客将对JDK1.8版本的相关类从源码层次进行介绍,JDK8的下载地址. 首先介绍JDK中所有类的基类——java.lang.Object. Object 类属于 java.lang 包,此包下 ...

  4. JDK1.7.0_45源码阅读<java.lang.Boolean>

    本文适合的人群 其实感觉写这个标题的内容没有必要,只要你觉得对你有帮助那么就适合你,对你没帮助那么就不适合你.毕竟我不是专业作者,但咱会尽力的.其实最重要的一点是我不希望浪费您宝贵时间. 简要把内容在 ...

  5. Java源码学习 -- java.lang.StringBuilder,java.lang.StringBuffer,java.lang.AbstractStringBuilder

    一直以来,都是看到网上说“ StringBuilder是线程不安全的,但运行效率高:StringBuffer 是线程安全的,但运行效率低”,然后默默记住:一个是线程安全.一个线程不安全,但对内在原因并 ...

  6. 从源码分析java.lang.String.isEmpty()

    今天在写代码的时候用到了java.lang.String.isEmpty()的这个方法,之前也用过,今天突发奇想,就看了看源码,了解了解它的实现方法,总结出来,大家可以交流交流. 通常情况下,我们使用 ...

  7. Java 源码赏析 - java.lang - Void

    被人鄙视了,于是也来读读源码... package java.lang; /** * The Void class is an uninstantiable placeholder class to ...

  8. JDK1.8源码(二)——java.lang.Integer类

    一.初识 1.介绍 int 是Java八大基本数据类型之一,占据 4 个字节,范围是 -2^31~2^31 - 1,即 -2147483648~2147483647.而 Integer 是 int 包 ...

  9. JDK1.8源码(三)——java.lang.String类

    一.概述 1.介绍 String是一个final类,不可被继承,代表不可变的字符序列,是一个类类型的变量.Java程序中的所有字符串字面量(如"abc")都作为此类的实例实现,&q ...

随机推荐

  1. ubuntu grub 操作

    系统开机时,按住 shift 进入 grub 1. 什么是 Grub GNU GRUB(GRand Unified Bootloader 简称"GRUB")是一个来自GNU项目的多 ...

  2. NVIDIA 显卡与 CUDA 在深度学习中的应用

    CUDA(Compute Unified Device Architecture),是显卡厂商 NVIDIA 推出的运算平台. 0. 配置 显卡驱动的下载地址:Drivers - Download N ...

  3. oracle授权grant

    alter any cluster 修改任意簇的权限 alter any index 修改任意索引的权限 alter any role 修改任意角色的权限 alter any sequence 修改任 ...

  4. EasyUI学习之menu and button(菜单和按钮)

    前言 今天下午的天气感觉格外的气闷,整个人有一种黏糊糊的感觉,格外的不舒服.加之立即要放假了了,感觉自己全然坐不住呢(节前综合症么).只是学习还是的继续的. 原定计划这篇文章本来应该是关于search ...

  5. WPF中利用RadialGradient模拟放大镜效果

    原文:WPF中利用RadialGradient模拟放大镜效果 --------------------------------------------------------------------- ...

  6. python 教程 第五章、 函数

    第五章. 函数 定义语句后面要加冒号 1)    定义函数 def sayHello(): print 'Hello World!' sayHello() 2)    变量作用域 LEGB原则 L本地 ...

  7. GoldenGate过程 abend,报错OGG-00868 ORA-02396: Exceeded Maximum Idle Time, Please Connect Again

    GoldenGate过程 abend,报错OGG-00868 ORA-02396: Exceeded Maximum Idle Time, Please Connect Again 参考原始: Gol ...

  8. docker端口映射或启动容器时报错Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen

    现象: [root@localhost ~]# docker run -d -p 9000:80 centos:httpd /bin/sh -c /usr/local/bin/start.shd5b2 ...

  9. 【C++】【TinyXml】xml文件的读写功能使用——写xml文件

    TinyXml工具是常用比较简单的C++中xml读写的工具 需要加载 #include "TinyXml\tinyxml.h" 在TinyXML中,根据XML的各种元素来定义了一些 ...

  10. WPF 4 DataGrid 控件(进阶篇二)

    原文:WPF 4 DataGrid 控件(进阶篇二)      上一篇<WPF 4 DataGrid 控件(进阶篇一)>中我们通过DataGridTemplateColumn 类自定义编辑 ...