While learning the source code of the JDK, I came across some interesting and useful methods. Before, if I wanted to use these tools, I would first think of commons-lang and Guava language extensions, but now if I am writing some demos, I can do it using native. Of course, we can’t deny that these language extensions are almost always included in our daily work projects, and their direct use makes for uniform programming styles, as well as support for older JDK versions. The following collection of code snippets may or may not grow over time.

java.util.Objects

Java.util.Objects utility class, I feel useful to several methods

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; }}Copy the code

In addition, you should learn the proper specification for writing utility classes from Objects,

  • Defined as final class
  • Define only one constructor with no arguments and throw an assertion error to prevent reflection from calling it
  • Utility methods are static methods
  • Only unchecked exceptions are thrown in static methods

java.lang.System

This was probably first seen in the Hello World program and is one of its recommended methods

    /**
     * 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);
Copy the code

The comment makes it clear that you can use an Object instance class to get the hash value regardless of whether the class overrides the Object hashCode method.

Gets the type parameter of the generic class

We can take a hint from the following code, which comes from HashMap,

/** * 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; }Copy the code

The logic here is to get class C, then get the interface Comparable

that it implements, then get the type parameter C from that Comparable

, and then compare whether the two types are equal. Although we’ve always heard that Generics in Java are type erasures, here we can get the parameter types of generics. As usual with a demo test,

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; }}}Copy the code

sun.reflect.Reflection

This utility class is related to reflection to let you know that there is such a method

@CallerSensitive public static native Class<? > getCallerClass();Copy the code

The first time I saw this method was in the getConnection method in java.sql.DriverManager

@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())); }Copy the code

Reflection. GetCallerClass () is a native method, returns the Class
type, which is used in DriverManager to get the corresponding ClassLoader, as seen in Java 8. In Java 7, DriverManager provides native methods to get a ClassLoader

/* Returns the caller's class loader, or null if none */
private static native ClassLoader getCallerClassLoader();
Copy the code

Let’s try calling this method with a piece of code

public class CalleeApp {

    public void call() {
        Class<?> clazz = Reflection.getCallerClass();
        System.out.println("Hello " + clazz);
    }
}
Copy the code
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(); }}}Copy the code

Executing the main method throws an exception

Exception in thread "main" java.lang.InternalError: CallerSensitive annotation expected at frame 1
Copy the code

This error message says that we are missing a CallerSensitive annotation at the beginning of the function call stack. Observe that the getConnection method of DriverManager does have such an annotation. What if you annotated CalleeApp’s call?

Object.wait(long timeout, int nanos)

This is a way to play cute, and the original meaning of this is in the notes,

    /*
     * <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>
     */
Copy the code

The nano is a nanosecond unit of time. And the way it works is this,

    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);
    }
Copy the code

In addition to checking the value range of the passed parameter, the use of Nano is only to determine whether the variable is greater than 0, and if so, to add 1 to timeout, which only adds 1 millisecond time and does not reflect the refinement.

The attached

  • you-dont-need-serial
  • Using Reflection. GetCallerClass () problems