在學習JDK的源碼過程當中我遇到了一些有趣有用的方法,在此以前若是要使用這些工具方法,我首先會想到的是commons-lang
和guava
這樣的語言擴展包,但如今若是是寫一些demo,使用原生便可達到目的。固然咱們也不可否認它們的做用,在平時的工做項目中幾乎都會引入這些語言擴展包,直接使用他們也使得編程風格統一,並且還可以對低版本的JDK提供支持。
如下收集的代碼片斷可能會逐漸增長,也可能不會。html
java.util.Objects
工具類,我以爲好用的幾個方法java
public static boolean equals(Object var0, Object var1) { return var0 == var1 || var0 != null && var0.equals(var1); } public static int hashCode(Object var0) { return var0 != null ? var0.hashCode() : 0; } public static <T> T requireNonNull(T var0) { if (var0 == null) { throw new NullPointerException(); } else { return var0; } } public static <T> T requireNonNull(T var0, String var1) { if (var0 == null) { throw new NullPointerException(var1); } else { return var0; } }
除此以外還應該從Objects
學習到編寫工具類的正確的規範,sql
這個最先應該是在Hello World程序中見到的,推薦它的一個方法編程
/** * Returns the same hash code for the given object as * would be returned by the default method hashCode(), * whether or not the given object's class overrides * hashCode(). * The hash code for the null reference is zero. * * @param x object for which the hashCode is to be calculated * @return the hashCode * @since JDK1.1 */ public static native int identityHashCode(Object x);
註釋寫得很明白了,無論一個對象實例的class有沒有覆蓋Object的hashCode方法,都能使用這個方法得到hash值。segmentfault
咱們能夠從如下代碼得到提示,代碼來自HashMap
,app
/** * Returns x's Class if it is of the form "class C implements * Comparable<C>", else null. */ static Class<?> comparableClassFor(Object x) { if (x instanceof Comparable) { Class<?> c; Type[] ts, as; Type t; ParameterizedType p; if ((c = x.getClass()) == String.class) // bypass checks return c; if ((ts = c.getGenericInterfaces()) != null) { for (int i = 0; i < ts.length; ++i) { if (((t = ts[i]) instanceof ParameterizedType) && ((p = (ParameterizedType)t).getRawType() == Comparable.class) && (as = p.getActualTypeArguments()) != null && as.length == 1 && as[0] == c) // type arg is c return c; } } } return null; }
這裏的邏輯是得到類C
,而後獲取它實現的接口Comparable<C>
,而後從這個Comparable<C>
中得到類型參數C
,而後比較這兩個類型是否相等。雖然咱們一直據說Java的泛型是類型擦除式,可是在這裏咱們是能夠得到泛型的參數類型的。照例用一段demo測試一下,ide
public class ParameterApp { public static void main(String[] args) { StringList list = new StringList(); Class<?> clazz = getTypeArgument(list); System.out.println(clazz.getName()); } static Class<?> getTypeArgument(Object x) { if (x instanceof Collection) { Class<?> c = x.getClass(); Type[] ts, as; Type t; ParameterizedType p; if ((ts = c.getGenericInterfaces()) != null) { for (int i = 0; i < ts.length; ++i) { if (((t = ts[i]) instanceof ParameterizedType) && ((as = ((ParameterizedType)t).getActualTypeArguments()) != null) && as.length == 1) // type arg is c return (Class<?>) as[0]; } } } return null; } static class StringList extends AbstractList<String> implements List<String> { @Override public String get(int i) { return null; } @Override public int size() { return 0; } } }
這個工具類是和反射相關的,讓你們知道有這麼一個方法函數
@CallerSensitive public static native Class<?> getCallerClass();
我第一次見到這個方法是在java.sql.DriverManager
中的getConnection
方法中見到的工具
@CallerSensitive public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties(); if (user != null) { info.put("user", user); } if (password != null) { info.put("password", password); } return (getConnection(url, info, Reflection.getCallerClass())); }
Reflection.getCallerClass()
是一個native
方法,返回的是Class<?>
類型,在DriverManager
中使用它的目的是爲了得到相應的ClassLoader
,上面的代碼是在Java 8中見到的。其中在Java 7中爲得到ClassLoader
,DriverManager
就直接提供了native
的方法學習
/* Returns the caller's class loader, or null if none */ private static native ClassLoader getCallerClassLoader();
咱們用一段代碼嘗試調用這個方法
public class CalleeApp { public void call() { Class<?> clazz = Reflection.getCallerClass(); System.out.println("Hello " + clazz); } }
public class CallerApp { public static void main(String[] args) { CalleeApp app = new CalleeApp(); Caller1 c1 = new Caller1(); c1.run(app); } static class Caller1 { void run(CalleeApp calleeApp) { if (calleeApp == null) { throw new IllegalArgumentException("callee can not be null"); } calleeApp.call(); } } }
執行main方法會拋出異常
Exception in thread "main" java.lang.InternalError: CallerSensitive annotation expected at frame 1
這個錯誤信息說的是咱們缺乏在函數調用棧開始位置添加CallerSensitive
註解,觀察DriverManager
的getConnection
方法確實是有這麼個註解的。
那若是給CalleeApp
的call
加上註解,那結果又會怎樣呢?
這個方法是來賣萌,它的本義在註釋是這樣子寫的,
/* * <p> * This method is similar to the {@code wait} method of one * argument, but it allows finer control over the amount of time to * wait for a notification before giving up. The amount of real time, * measured in nanoseconds, is given by: * <blockquote> * <pre> * 1000000*timeout+nanos</pre></blockquote> * <p> */
意思是提供精細化的時間衡量,nano
但是納秒單位啊!!!
而它的實現倒是這樣的,
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); }
除了對傳入參數的數值範圍校驗外,對nano
的使用牢牢是判斷這個變量是否大於0,是則給timeout
加1,這只是增長了1毫秒的時間,並無體現出了精細化的地方。