资讯专栏INFORMATION COLUMN

一些我认为有用有趣的JDK方法

lx1036 / 2666人阅读

摘要:在学习的源码过程中我遇到了一些有趣有用的方法,在此之前如果要使用这些工具方法,我首先会想到的是和这样的语言扩展包,但现在如果是写一些,使用原生即可达到目的。

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

java.util.Objects

java.util.Objects工具类,我觉得好用的几个方法

    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 requireNonNull(T var0) {
        if (var0 == null) {
            throw new NullPointerException();
        } else {
            return var0;
        }
    }

    public static  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程序中见到的,推荐它的一个方法

    /**
     * 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

    /**
     * Returns x"s Class if it is of the form "class C implements
     * Comparable", 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,然后从这个Comparable中获得类型参数C,然后比较这两个类型是否相等。虽然我们一直听说Java的泛型是类型擦除式,但是在这里我们是可以获得泛型的参数类型的。照例用一段demo测试一下,

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 implements List {

        @Override
        public String get(int i) {
            return null;
        }

        @Override
        public int size() {
            return 0;
        }
    }
}
sun.reflect.Reflection

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

    @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中为获得ClassLoaderDriverManager就直接提供了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注解,观察DriverManagergetConnection方法确实是有这么个注解的。
那如果给CalleeAppcall加上注解,那结果又会怎样呢?

Object.wait(long timeout, int nanos)

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

    /*
     * 

* 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: *

*
     * 1000000*timeout+nanos
*

*/

意思是提供精细化的时间衡量,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毫秒的时间,并没有体现出了精细化的地方。

you-dont-need-serial

Reflection.getCallerClass()使用的问题

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69032.html

相关文章

  • 源码|jdk源码之Object及装箱类型分析

    摘要:作为条件变量的的不仅可以认为内嵌了一把锁,还内嵌了一个条件变量。操作条件变量的函数将当前线程在条件变量上阻塞,一般是为了等待其他线程的某件事情执行完成。其它装箱类其它装箱类的代码这里就不分析了。重点关注下各装箱类的缓存范围。 jdk源码读到现在这里,重要的集合类也读了一部分了。集合类再往下读的话,就要涉及到两个方向。第一,是比较典型的但是不常用的数据结构,这部分我准备将数据结构复习、回...

    VioletJack 评论0 收藏0
  • 前端学习资源

    摘要:掘金日报第四期使用怎么能不知道这些插件合集掘金日报主打分享优质深度技术内容,技术内容分前端后端产品设计工具资源和一些有趣的东西。目前已经涵盖了的相关资源链接,供大家参考与学习。 【掘金日报】第四期 使用Sublime?怎么能不知道这些 Sublime 插件合集! 掘金日报主打分享优质深度技术内容,技术内容分:前端、后端、Android、iOS、产品设计、工具资源和一些有趣的东西。 前端...

    xzavier 评论0 收藏0
  • 前端学习资源

    摘要:掘金日报第四期使用怎么能不知道这些插件合集掘金日报主打分享优质深度技术内容,技术内容分前端后端产品设计工具资源和一些有趣的东西。目前已经涵盖了的相关资源链接,供大家参考与学习。 【掘金日报】第四期 使用Sublime?怎么能不知道这些 Sublime 插件合集! 掘金日报主打分享优质深度技术内容,技术内容分:前端、后端、Android、iOS、产品设计、工具资源和一些有趣的东西。 前端...

    weij 评论0 收藏0
  • LSTM入门必读:从基础知识到工作方式详解

    摘要:意味着完全保持,意味着完全丢弃。卡比兽写这篇博文的时间我本可以抓一百只,请看下面的漫画。神经网络神经网络会以的概率判定输入图片中的卡比兽正在淋浴,以的概率判定卡比兽正在喝水,以的概率判定卡比兽正在遭遇袭击。最终结果是卡比兽正在遭遇袭击 我第一次学习 LSTM 的时候,它就吸引了我的眼球。事实证明 LSTM 是对神经网络的一个相当简单的扩展,而且在最近几年里深度学习所实现的惊人成就背后都有它们...

    alanoddsoff 评论0 收藏0
  • 21 个VSCode 快捷键,让代码更快,更有趣

    摘要:在这篇文章中,我将列出我最喜欢的快捷键,这些快捷键让我更快的编写代码,也让编码变得更有趣,以下是个快捷键,分享给你。打开键盘快捷键或,搜索。在中,启动性能是很重要的。逐个选择文本可以通过快捷键右箭头右箭头和左箭头左箭头逐个选择文本。 为了保证的可读性,本文采用意译而非直译。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 注意:自己尝试的时候,Mac(17, p...

    elina 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<