JDK8源码分析
基于JDK1.8------java lang Object
Object的类中的方法(13个方法)
registerNatives()
getClass()
hashCode()
equals()
clone()
toString()
notify()
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<T>
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<E>是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 在栈里面声明一块地址,里面没有指向的堆地址