JDK源码分析
基于JDK1.8------java lang Object
Object的类中的方法(13个方法)
registerNatives()
getClass()
hashCode()
equals()
clone()
toString()
notify()
notifyAll()
wait() 有三个方法重载
finalize()
源码:
/**
* Class {@code Object} is the root of the class hierarchy.
* Every class has {@code Object} as a superclass. All objects,
* including arrays, implement the methods of this class.
*
* @author unascribed
* @see java.lang.Class
* @since JDK1.0
*/
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
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 > 0) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize() throws Throwable { }
}
为什么使用java lang Object包下面不需要导入包?
因为java.lang.Object是除了它自身之外的所有类的父类,所以不需要导入
导入包的方式: 1.单类型导入(提倡使用): 具体的名字直到具体到包的吓得名字 —import java.util.Iterator;
2.按需求类型导包:import java.util.* 意思为下面你用到什么类型的包,系统就会给你导入你代码中需要的包(并不是将util包下面的类全部导入!)
小结:单类型导入会提高代码的运行速度,因为会针对性的去所对应的文件夹下寻找类及导入当前类中。
equals(Object obj)
public boolean equals(Object obj) {
return (this == obj);
}
先介绍下“==”符号 每次生成对对象或者属性的同时会给改内容生成一个地址编码(经过一定算法后为hashcode)==比较的是两个对象或者属性是否有一个hashcode值,在Object源码看来 equal 与 == 是等价的 但是!每当调用equal方法的this都会重写这个equal方法,如果是自己写的类可以重写方法equal来定义自己的方法——上面叫两个对象相同如果是系统自带的类例如String对象的源码如下:
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;
}
分析:this == anObject
如果调用这个对象的他们的hashcode的值一样的话 那么确定他们是同一个字符串。
如果调用这个对象的是String的指向类型,那么就把继续判断,长度,转为字符数组后每个字符的内容是否相等,如果都相等的话返回的true。
注意点:比较时候要排除对象为空的情况 非空的x x.equal(null) 返回值为false
小结:== 比较基本数据类型为比较的值是否相同 比较引用数据类型 比较的是hashcode值。
equal() 比较引用数据类型 比较他们的Hashcode 基本数据类型不能使用其方法。
toSting()
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
返回值为String类型 返回的内容为 调用此访的对象所在的类的名字+一个@符号+Integer类型的的hash值加密后的数值(可以理解为内存地址)
打印某个对象时候默认的调用toString方法。
wait()
线程锁时候使用:将某个获得锁对象并且在Runnable的状态下 讲此线程转为等待池中。
notify()/notifyAll()
这个是使用锁对象线程是的时候才能使用的方法得到,先调用wait方法,在使用noti()/notifAll()使得被wait的线程可以随机分配锁对象的机会(wait等待池中转到锁等待池中再次获得锁对象)
finalize 方法
这个方法是有jvm自动调用,进行垃圾回收(简单介绍垃圾回收:该对象不再会有人指向它或者他为空的时候,jvm会自动调用此方法)
registerNatives()
private static native void registerNatives();
static {
registerNatives();
}
此方法是native修饰的说明这个方法是c或者c++编写的;System.loadLibrary(“helloJNI”);加载动态库,参数 helloJNI 是动态库的名字
native 用来修饰方法,用 native 声明的方法表示告知 JVM 调用,该方法在外部定义,我们可以用任何语言去实现它。 简单地讲,一个native Method就是一个 Java 调用非 Java 代码的接口。
native 语法:
①、修饰方法的位置必须在返回类型之前,和其余的方法控制符前后关系不受限制。
②、不能用 abstract 修饰,也没有方法体,也没有左右大括号。
③、返回值可以是任意类型
我们在日常编程中看到native修饰的方法,只需要知道这个方法的作用是什么,至于别的就不用管了,操作系统会给我们实现。
java lang Integer
public final class Integer extends Number implements Comparable<Integer>
这个类是final修饰的 不可以被继承 继承了Number类和实现了Cmparable接口,Number 类是一个抽象类,8中基本数据类型的包装类除了Character 和 Boolean 没有继承该类外,剩下的都继承了 Number 类,该类的方法用于各种数据类型的转换。Comparable 接口就一个 compareTo 方法,用于元素之间的大小比较,下面会对这些方法详细展开介绍。
number抽象类
public abstract class Number implements java.io.Serializable {
Comparable
Comparable接口的实现方法
public interface Comparable<T> {
public int compareTo(T o);
}
接下里就看看怎么实现Integer中的Comparable接口的
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
这个接口实现方法调用了自己里面的写的方法 比较两个数的大小
如果 x < y 返回 -1
如果 x == y 返回 0
如果 x > y 返回 1
Integer构造器
public Integer(int value) {
this.value = value;
}
这个在new的时候讲一个基本数据类型返回 Integer类型
//String必须是第一位为“-或者+” 其他均为 0-9 a-z
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
public static int parseInt(String s, int radix)
throws NumberFormatException
{
if (s == null) {
throw new NumberFormatException("null");
}
//如果转换的radix(默认是10)<2 则抛出数字格式异常,因为进制最小是 2 进制
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
//如果转换的radix(默认是10)>36 则抛出数字格式异常,因为0到9一共10位,a到z一共26位,所以一共36位
//也就是最高只能有36进制数
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
toString()三个方法的重载
public static String toString(int i, int radix) {
//第一个参数为需要转为的数据 第二个数为转为数据的进制数 最后返回一个字符串
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
/* Use the faster version */
if (radix == 10) {
return toString(i);
}
char buf[] = new char[33];
boolean negative = (i < 0);
int charPos = 32;
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = digits[-i];
if (negative) {
buf[--charPos] = '-';
}
return new String(buf, charPos, (33 - charPos));
}
parseInt(String s, int radix)
这个源码和Integer(String S ,int)一样
valueOf(int i)
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
调用的是构造方法里面的讲int转为Integer类型
Max()
public static int max(int a, int b) {
return Math.max(a, b);
}
//math的max
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
调用的是Math的max的方法三目运算符
java lang String
类的特点
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
是final修饰的
接着实现了 Serializable接口,这是一个序列化标志接口,还实现了 Comparable 接口,用于比较两个字符串的大小(按顺序比较单个字符的ASCII码),后面会有具体方法实现;最后实现了 CharSequence 接口,表示是一个有序字符的集合。
String 的底层存放字符串的是private final char value[];
String(Stringbuffered buffer)
public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
//arrays的copyOf方法
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
//system的arraycopy方法 此方法是其他语言编写的
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
将可变的字符串转为不可变字符串-----意味着吧buffer里面的数据放到定长数组里面
toCharArray()
public char[] toCharArray() {
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;
}
equals(Object anObject)
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;
}
首先比较他们的hashcode是否相等 如果相等的话那么他们就是相等的,如果他们的指向类型的是属于String的指向类型或者是String类型的话在进行一个个字符进行判断
indexof()
public int indexOf(String str) {
return indexOf(str, 0);
}
public int indexOf(int ch, int fromIndex) {
final int max = value.length;//max等于字符的长度
if (fromIndex < 0) {//指定索引的位置如果小于0,默认从 0 开始搜索
fromIndex = 0;
} else if (fromIndex >= max) {
//如果指定索引值大于等于字符的长度(因为是数组,下标最多只能是max-1),直接返回-1
return -1;
}
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {//一个char占用两个字节,如果ch小于2的16次方(65536),绝大多数字符都在此范围内
final char[] value = this.value;
for (int i = fromIndex; i < max; i++) {//for循环依次判断字符串每个字符是否和指定字符相等
if (value[i] == ch) {
return i;//存在相等的字符,返回第一次出现该字符的索引位置,并终止循环
}
}
return -1;//不存在相等的字符,则返回 -1
} else {//当字符大于 65536时,处理的少数情况,该方法会首先判断是否是有效字符,然后依次进行比较
return indexOfSupplementary(ch, fromIndex);
}
}
intern()
public native String intern();
可以常量池里面(前提是常量里面没吃这个常量对象)
总结:String真的是不可变的嘛?不是!可以通过反射机制获取String对象,在获得定义的变量------String.class.getDeclaredField(“value”);直接获取堆里面的数组对象,对其进行修改(前提要设置setAccessible(true))因为这个是value是private修饰的
new String生成的是对象!String s=“ ”生成的常量放在常量池里面 可供下次使用,若再有相同值的String可以直接饮用之前使用过的
java util Arrays
ArrayList是Arrays 的内部类
这个方法返回的 ArrayList 不是我们常用的集合类 java.util.ArrayList。这里的 ArrayList 是 Arrays 的一个内部类 java.util.Arrays.ArrayList。只能对其进行查看修改不能对其删除和增加
private static class ArrayList<E> extends AbstractList<E>
eg:
list list =Arrays.aslist(1,2,3,4,5);
asList()
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
aslist接受的是包装类型的数据
public void test(){
int [] a=new int[]{1,23,4,6,8};
List ints = Arrays.asList(a);
///ints.size()为1 只能吧整个int[] 进行泛型化
for (int i = 0; i <ints.size() ; i++) {
System.out.println(ints.get(i));
}
}}
//输出结果为[I@306a30c7数组对象
//ps:在 Arrays.asList 中,方法声明为 <T> List<T> asList(T... a)。该方法接收一个可变参数,并且这个可变参数类型是作为泛型的参数。我们知道基本数据类型是不能作为泛型的参数的,但是数组是引用类型,所以数组是可以泛型化的,于是 int[] 作为了整个参数类型,而不是 int 作为参数类型。
sort()
有十几种方法进行重载
sort(int i)
public static void sort(int[] a) {
DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}
//在 Arrays.sort 方法内部调用 DualPivotQuicksort.sort 方法,这个方法的源码很长,分别对于数组的长度进行了各种算法的划//分,//包括快速排序,插入排序,冒泡排序都有使用。详细源码可以参考https://www.cnblogs.com/yuxiaofei93/p/5722714.html
因为具体的算法俺也不会 小辫子也只能看到这里 太长的源码看的头发也没有了!
copeOf()
public static int[] copyOf(int[] original, int newLength) {
int[] copy = new int[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
equal(int i)
public static boolean equals(int[] a, int[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++)
if (a[i] != a2[i])
return false;
return true;
}
首先判断会否是同一个对象,或者判断他们是不是都为为空,若为空则那么返回为false 再或者比较他们的长度在比较他们每个元素的内容是否相同
toString()
public static String toString(char[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(a[i]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
首先判断是否为空—空的就输出null字符 如果里面声明也没有的话返回一个[] 在否则的话进行么个数组的遍历放到一个Stringbuilder里面
分析: String [] s=null 在栈里面声明一块地址,里面没有指向的堆地址
String [] s={} 在栈里面有一块地址 并且指向了堆里面的内存,但是堆里面得什么都能不放