前言
- 为什么阅读源码?
学习设计模式和思维。总之,知道自己有多菜,在不断学习的过程中发现自身不足并弥补,才能进步。
- 如何阅读
阅读顺序参考:https://blog.csdn.net/qq_21033663/article/details/79571506
结合aip:https://docs.oracle.com/javase/8/docs/api/
1.Object类
类 Object 是类层次结构的根类,每个类都使用 Object 作为超类,所有对象、包括数组都实现了Object类的方法。简而言之,所有类都有Object类中的方法。
//构造函数
Object()
private static native void registerNatives();
static {
registerNatives();
}
Object类中一开始的4行代码,关于registerNatives():
- native:本地方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。native方法在JVM中运行时数据区也和其它方法不一样,它有专门的本地方法栈。native方法主要用于加载文件和动态链接库。由此可知,本地方法的实现是由其他语言编写并保存在动态连接库中,因而在java类中不需要方法实现。
- 静态代码块:用于初始化类,为类的属性初始化。每个静态代码块只会执行一次。
- 代码功能:先定义了registerNatives()方法,然后当该类被加载的时候,调用该方法完成对该类中本地方法的注册。
当包含registerNatives()方法的类被加载的时候,注册的方法就是该类所包含的除了registerNatives()方法以外的所有本地方法。
一个Java程序要想调用一个本地方法,需要执行两个步骤:第一,通过System.loadLibrary()将包含本地方法实现的动态文件加载进内存;第二,当Java程序需要调用本地方法时,虚拟机在加载的动态文件中定位并链接该本地方法,从而得以执行本地方法。registerNatives()方法的作用就是取代第二步,让程序主动将本地方法链接到调用方,当Java程序需要调用本地方法时就可以直接调用,而不需要虚拟机再去定位并链接。
- 使用registerNatives()方法的三点好处:
- 通过registerNatives方法在类被加载的时候就主动将本地方法链接到调用方,比当方法被使用时再由虚拟机来定位和链接更方便有效;
- 如果本地方法在程序运行中更新了,可以通过调用registerNative方法进行更新;
- Java程序需要调用一个本地应用提供的方法时,因为虚拟机只会检索本地动态库,因而虚拟机是无法定位到本地方法实现的,这个时候就只能使用registerNatives()方法进行主动链接。
- 通过registerNatives()方法,在定义本地方法实现的时候,可以不遵守JNI命名规范。JNI命名规范要求本地方法名由“包名”+“方法名”构成。
Object类中的native方法:
//Returns the runtime class of this Object.
public final native Class<?> getClass();
//Returns a hash code value for the object.
public native int hashCode();
//Creates and returns a copy of this object.
protected native Object clone() throws CloneNotSupportedException;
//Wakes up a single thread that is waiting on this object's monitor.
public final native void notify();
//Wakes up all threads that are waiting on this object's monitor.
public final native void notifyAll();
//Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
public final native void wait(long timeout) throws InterruptedException;
其他方法:
public boolean equals(Object obj) {
return (this == obj);
}
- equals()在实际开发中一般都要重写,因为obj1 == obj2只判断了两个对象的地址值,如果该对象的成员变量中包含了引用类型的变量,则需要进一步判断。
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString() demo:
- toString()返回全路径名称+哈希值;一般也需要重写;
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 > 0) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
- Object类中wait有三个重载方法,同时必须捕获非运行时异常InterruptedException。
- wait() :需要notify ,notifyAll才能唤醒;
- wait(long timeout) :经过timeout 超时后,若未被唤醒,则自动唤醒;
- wait(timeout, nanos) :经过timeout 超时后,若未被唤醒,则自动唤醒。相对wait(long timeout) 更加精确时间。
-
方法都必须在synchronized 同步关键字所限定的作用域中调用,否则会报错java.lang.IllegalMonitorStateException ,意思是因为没有同步,所以线程对对象锁的状态是不确定的,不能调用这些方法。
protected void finalize() throws Throwable { }
- finalize()方法是Java中Object类的一个空实现方法。 作用:GC准备回收该对象的内存时,会先调用finalize()。关键字protected是防止在该类之外定义的代码访问finalize()标识符。
2.String类
String类用final关键字修饰,类不能被继承,不能被覆盖,以及final类在执行速度方面比一般类快。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/*** 成员属性 ***/
// 底层利用字符数组实现,final修饰
private final char value[];
// String对象的hashcode缓存,考虑String不可变特性,hash码频繁使用,因此直接记录下该值也是一种优化。默认值为 0.
private int hash;
// serialVersionUID 支持序列化和反序列化支持
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
// native方法 intern()
public native String intern();
}
String类实现三个接口:
- Serializable:可序列化;
- Comparable:类的实例化对象之间可比较;
- CharSequence:此接口对多种不同的对char访问的统一接口;String定义的字符串只能读,CharSequence定义的字符串是可读可写的;
String类的intern()方法:
在用new时,String都是在堆上创建字符串对象。当调用 intern() 方法时,编译器会将字符串添加到常量池中(stringTable维护),并返回指向该常量的引用。
String构造函数:
public static void main(String[] args) throws UnsupportedEncodingException {
/*
*String类构造函数demo
*/
// 无参构造
String s1 = new String();
System.out.println(s1.hashCode()=="".hashCode()); //hash值默认为0; 0==0 true
String s = "123";
String s2 = new String(s);
System.out.println(s2 == s); // false == 比较的是对象内存地址值,s和s2是堆中的不同对象,所有false;
// System.out.println(s2 == "123"); false 地址值不同,hash值相同
// System.out.println(s == "123"); true
System.out.println(s2.hashCode() == s.hashCode()); // true; 比较的是String中的成员对象hash的值
String s3 = "123";
System.out.println(s == s3); // true
//用字符数组构造
String s4 = new String(new char[] {'a', 'b'});
String s5 = new String(new char[] {'a', 'b','c'}, 1, 2); //s5 = bc;
String s6 = new String(new int[] {65,97,100},0,2); // int数组 用ASCII码构造 Aa
String s7 = new String(new byte[]{65,2,3}, "GBK"); //指定编码集
// StringBuffer、StringBuilder构造
String s8 = new String(new StringBuffer());
String s9 = new String(new StringBuilder());
}
贴几个源码:
public String() {
this.value = "".value;
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}
- StringBuffer不是线程安全,要用synchronized关键字;StringBuilder线程安全。
@Override
public int length() {
return value.length;
}
@Override
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
@Override
public CharSequence subSequence(int start, int end) {
return this.substring(start, end);
}
- 实现CharSequence接口的3个方法;
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
- 实现 Comparable接口的compareTo():比较两个字符串的字典顺序。用字符串1跟字符串2作比较,如果字符串1的字典顺序在字符串2前面,则返回一个负数。若在后面,则返回一个正数。若两个字符串的字典顺序相同,则返回0。
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
- 将当前字符串从start到end-1位置上的字符复制到字符数组c中,并从c的offset处开始存放。
Arrays.copyOf()和System.arrayCopy()的区别:
Arrays.copyOf()不仅仅只是拷贝数组中的元素,在拷贝元素时,会创建一个新的数组对象。而System.arrayCopy只拷贝已经存在数组元素。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
// 忽略大小写
public boolean equalsIgnoreCase(String anotherString) {
return (this == anotherString) ? true
: (anotherString != null)
&& (anotherString.value.length == value.length)
&& regionMatches(true, 0, anotherString, 0, value.length);
}
- instanceof:Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
- 首先,判断引用值是否相等,相等即true;否则,判断类型是否匹配,类型相同,长度相等,逐个比较字符是否一样,完全符合,则返回ture。(如果两个对象判断相等,判断类型)
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 8575799808933029326L;
public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
c1 = Character.toLowerCase(c1);
c2 = Character.toLowerCase(c2);
if (c1 != c2) {
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2;
}
/** Replaces the de-serialized object. */
private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
}
-
CaseInsensitiveComparator静态内部类:compare方法实现String对象的大小写不敏感比较。
- 存疑:为什么设计成静态内部类?
public boolean startsWith(String prefix, int toffset) {
char ta[] = value;
int to = toffset;
char pa[] = prefix.value;
int po = 0;
int pc = prefix.value.length;
// Note: toffset might be near -1>>>1.
if ((toffset < 0) || (toffset > value.length - pc)) {
return false;
}
while (--pc >= 0) {
if (ta[to++] != pa[po++]) {
return false;
}
}
return true;
}
public boolean endsWith(String suffix) {
return startsWith(suffix, value.length - suffix.value.length);
}
- 子串截取
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
- 字符替换
- 哪怕多做些循环判断,也要尽量避免new新的对象;
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}
- 分割字符
public String[] split(String regex, int limit) {
/* fastpath if the regex is a
(1)one-char String and this character is not one of the
RegEx's meta characters ".$|()[{^?*+\\", or
(2)two-char String and the first char is the backslash and
the second is not the ascii digit or ascii letter.
*/
char ch = 0;
if (((regex.value.length == 1 &&
".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
(regex.length() == 2 &&
regex.charAt(0) == '\\' &&
(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
((ch-'a')|('z'-ch)) < 0 &&
((ch-'A')|('Z'-ch)) < 0)) &&
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE))
{
int off = 0;
int next = 0;
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<>();
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
list.add(substring(off, value.length));
off = value.length;
break;
}
}
// If no match was found, return this
if (off == 0)
return new String[]{this};
// Add remaining segment
if (!limited || list.size() < limit)
list.add(substring(off, value.length));
// Construct result
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
resultSize--;
}
}
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}
public String trim() {
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */
while ((st < len) && (val[st] <= ' ')) {
st++;
}
while ((st < len) && (val[len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}
3.AbstractStringBuilder
这个抽象类是StringBuilder和StringBuffer的直接父类。可以认为AbstractStringBuilder 就是对于可变字符序列的这一概念的描述。
他提供了可变字符序列的一个基本协议约定,也就是基本的功能方法作为一个抽象类, 并且也提供了一部分默认的实现;StringBuffer和StringBuilder都是可变的字符序列,所以他们都实现了AbstractStringBuilder。
类声明:
abstract class AbstractStringBuilder implements Appendable, CharSequence{}
实现了两个接口,其中CharSequence这个字符序列的接口已经很熟悉了:
- 该接口规定了需要实现该字符序列的长度:length();
- 可以取得下标为index的的字符:charAt(int index);
- 可以得到该字符序列的一个子字符序列: subSequence(int start, int end);
- 规定了该字符序列的String版本(重写了父类Object的toString()):toString();
Appendable接口顾名思义,定义添加的’规则’:
- append(CharSequence csq) throws IOException:如何添加一个字符序列
- append(CharSequence csq, int start, int end) throws IOException:如何添加一个字符序列的一部分
- append(char c) throws IOException:如何添加一个字符
成员变量:
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
构造函数:
AbstractStringBuilder() {
}
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
方法:
4.StringBuffer
类声明:
成员变量:
构造函数:
方法:
5.StringBuilder
类声明:
成员变量:
构造函数:
方法:
6.HashMap
public static void main(String[] args) {
HashMap map1 = new HashMap<String,String>(8,(float) (0.8));
HashMap map2 = new HashMap<String,String>();
map1.put("1", "aaa");
map1.put("3", "ccc");
map2.put("a", "jony");
map2.put("1", "kiki");
map1.put(null, null);
System.out.println(map1.size()); //size=3-HashMap允许存放null键值对
System.out.println(map1.put("1", "s")); // put方法-如果key已存在,替换,并返回原value;
map2.putAll(map1); //putAll方法-将map1中所有mappings复制到map2中,对于map2之前已有key对应的value将被map1对应的value覆盖,其余map2的键值对不受影响;
System.out.println(map2.size());
System.out.println(map2.get("1"));
System.out.println(map1.get("3"));
System.out.println(map1.containsKey("2")); // 是否包含某个key
System.out.println(map1.containsValue("ccc")); // 是否包含某个value
Set<String> set = map1.keySet(); // 返回所有key构成的集合
Collection set2 = map1.values(); //返回所有value构成的集合
Set<String> set3 = map1.entrySet(); //返回所有Entry构成的集合
System.out.println(map1.replace("1", "ee"));
System.out.println(map2.remove("a")); //移除指定key值对应的mapping,如果指定key不存在,返回null
}