从JDK源码看有趣的方法

转载 2018年04月17日 16:39:44
在学习JDK的源码过程中我遇到了一些有趣有用的方法,在此之前如果要使用这些工具方法,我首先会想到的是commons-langguava这样的语言扩展包,但现在如果是写一些demo,使用原生即可达到目的。当然我们也不能否认它们的作用,在平时的工作项目中几乎都会引入这些语言扩展包,直接使用他们也使得编程风格统一,而且还能够对低版本的JDK提供支持。

以下收集的代码片段可能会逐渐增加,也可能不会。

<textarea readonly="readonly" name="code" class="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学习到编写工具类的正确的规范,

  • 定义为final class
  • 只定义一个无参的构造函数且抛出断言错误,防止被反射调用
  • 工具方法都是静态方法
  • 静态方法中只抛出unchecked异常

java.lang.System

这个最早应该是在Hello World程序中见到的,推荐它的一个方法

<textarea readonly="readonly" name="code" class="Java"> 
 /**
     * 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值。

获取泛型类的类型参数

我们可以从以下代码获得提示,代码来自HashMap

<textarea readonly="readonly" name="code" class="Java">
/**
     * 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测试一下,

<textarea readonly="readonly" name="code" class="Java">
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;
        }
    }
}

sun.reflect.Reflection

这个工具类是和反射相关的,让大家知道有这么一个方法

<textarea readonly="readonly" name="code" class="Java">
 @CallerSensitive
    public static native Class<?> getCallerClass();
我第一次见到这个方法是在java.sql.DriverManager中的getConnection方法中见到的
<textarea readonly="readonly" name="code" class="Java">
@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中为获得ClassLoaderDriverManager就直接提供了native的方法

<textarea readonly="readonly" name="code" class="Java">
/* Returns the caller's class loader, or null if none */
private static native ClassLoader getCallerClassLoader();
<textarea readonly="readonly" name="code" class="Java">
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();
        }
    }

}

public class CalleeApp { public void call() { Class<?> clazz = Reflection.getCallerClass(); System.out.println("Hello " + clazz); }}

我们用一段代码尝试调用这个方法

<textarea readonly="readonly" name="code" class="Java">
public class CalleeApp {

    public void call() {
        Class<?> clazz = Reflection.getCallerClass();
        System.out.println("Hello " + clazz);
    }
}
<textarea readonly="readonly" name="code" class="Java">
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注解,观察DriverManagergetConnection方法确实是有这么个注解的。

那如果给CalleeAppcall加上注解,那结果又会怎样呢?

Object.wait(long timeout, int nanos)

这个方法是来卖萌,它的本义在注释是这样子写的,

<textarea readonly="readonly" name="code" class="Java">
  /*
     * <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可是纳秒单位啊!!!
而它的实现却是这样的,
<textarea readonly="readonly" name="code" class="Java">
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毫秒的时间,并没有体现出了精细化的地方。



Retrofit 从入门封装到源码解析

从Retrofit的入门开始讲解,然后搭配Rxjava使用,主要讲解在实战项目中如何封装(主要涉及到OkHttp,部分涉及到Retrofit),最后会对源码进行解析,让你知其然,知其所以然。
  • 2017年02月21日 15:40

深入解析Java反射-invoke方法

博客原文:http://www.sczyh30.com/posts/Java/java-reflection-2/ 上篇文章中回顾了一下Java反射相关的基础内容。这一节我们来深入研究...
  • z3881006
  • z3881006
  • 2017-05-22 09:56:27
  • 1641

浅聊Java反射机制(三)

引入 即使没有学过反射,大家也一定会见过invoke方法。因为很多方法调用都是靠invoke方法,所以很多异常的抛出都会定位到invoke方法,比如下面的情形大家会很熟悉: java.la...
  • xiangxizhishi
  • xiangxizhishi
  • 2017-06-25 15:19:29
  • 413

深入解析Java反射 - invoke方法

引入 即使没有学过反射,大家也一定会见过invoke方法。因为很多方法调用都是靠invoke方法,所以很多异常的抛出都会定位到invoke方法,比如下面的情形大家会很熟悉: java.lang.Nul...
  • vikeyyyy
  • vikeyyyy
  • 2018-01-17 11:24:55
  • 119

java security code guider line

source: http://www.oracle.com/technetwork/java/seccodeguide-139067.html Secure Coding G...
  • haizhiguang
  • haizhiguang
  • 2015-03-23 09:51:22
  • 1027

Java ClassLoader 类加载 与 SOA后期优化

Java ClassLoader 类加载 与 SOA后期优化标签(空格分隔): jetty soa application 现在见到的一些应用部署方式(我见到的)只能说是我见到的这2种 - 1 ....
  • tianzhihen28
  • tianzhihen28
  • 2015-12-21 12:52:44
  • 313

GTK+ 之初

GTK入门导引 1. 简介   GTK (GIMP Toolkit) 起源於开发用来做为GIMP (General Image Manipulation Program)的一套工具. GTK建...
  • uunubt
  • uunubt
  • 2010-12-13 08:42:00
  • 740

gdb-- help all, 方便 Ctrl + F

Command class: aliases ni -- Step one instruction rc -- Continue program being debugged but run it ...
  • dengzhaoqun
  • dengzhaoqun
  • 2013-04-10 11:36:42
  • 1729

我的Doxygen配置

# Doxyfile 1.8.12 # This file describes the settings to be used by the documentation system # ...
  • niepangu
  • niepangu
  • 2016-11-25 19:58:30
  • 311

常见.Net 英文专业词汇收集

abstract class    抽象类 accelerator    快捷键 accelerator mapping    快捷键映射 accelerator table    快捷键对应表 ac...
  • qiuyu0619
  • qiuyu0619
  • 2006-01-18 23:01:00
  • 3177
收藏助手
不良信息举报
您举报文章:从JDK源码看有趣的方法
举报原因:
原因补充:

(最多只允许输入30个字)