专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序员的那些事  ·  印度把 DeepSeek ... ·  3 天前  
OSC开源社区  ·  宇树王兴兴早年创业分享引围观 ·  4 天前  
程序猿  ·  “未来 3 年内,Python 在 AI ... ·  4 天前  
程序员的那些事  ·  惊!小偷“零元购”后竟向 DeepSeek ... ·  4 天前  
程序员的那些事  ·  成人玩偶 + ... ·  5 天前  
51好读  ›  专栏  ›  SegmentFault思否

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

SegmentFault思否  · 公众号  · 程序员  · 2018-04-12 08:00

正文

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

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

java.util.Objects

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

  1.    public static boolean equals(Object var0, Object var1) {

  2.        return var0 == var1 || var0 != null && var0.equals(var1);

  3.    }

  4.    public static int hashCode(Object var0) {

  5.        return var0 != null ? var0.hashCode() : 0;

  6.    }

  7.    public static <T> T requireNonNull(T var0) {

  8.        if (var0 == null) {

  9.            throw new NullPointerException();

  10.        } else {

  11.            return var0;

  12.        }

  13.    }

  14.    public static <T> T requireNonNull(T var0, String var1) {

  15.        if (var0 == null) {

  16.             throw new NullPointerException(var1);

  17.        } else {

  18.            return var0;

  19.        }

  20.    }        

除此之外还应该从 Objects 学习到编写工具类的正确的规范:

  • 定义为final class

  • 只定义一个无参的构造函数且抛出断言错误,防止被反射调用

  • 工具方法都是静态方法

  • 静态方法中只抛出unchecked异常

java.lang.System

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

  1.    /**

  2.     * Returns the same hash code for the given object as

  3.     * would be returned by the default method hashCode(),

  4.     * whether or not the given object's class overrides

  5.     * hashCode().

  6.     * The hash code for the null reference is zero.

  7.     *

  8.     * @param x object for which the hashCode is to be calculated

  9.     * @return  the hashCode

  10.     * @since   JDK1.1

  11.     */

  12.    public static native int identityHashCode(Object x);

注释写得很明白了,不管一个对象实例的class有没有覆盖Object的hashCode方法,都能使用这个方法获得hash值。

获取泛型类的类型参数

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

  1.    /**

  2.     * Returns x's Class if it is of the form "class C implements

  3.     * Comparable", else null.

  4.     */

  5.    static Class> comparableClassFor(Object x) {

  6.        if (x instanceof Comparable) {

  7.            Class> c; Type[] ts, as; Type t; ParameterizedType p;

  8.            if ((c = x.getClass()) == String.class) // bypass checks

  9.                 return c;

  10.            if ((ts = c.getGenericInterfaces()) != null) {

  11.                for (int i = 0; i < ts.length; ++i) {

  12.                    if (((t = ts[i]) instanceof ParameterizedType) &&

  13.                        ((p = (ParameterizedType)t).getRawType() ==

  14.                         Comparable.class) &&

  15.                        (as = p.getActualTypeArguments()) != null &&

  16.                        as.length == 1 && as[0] == c) // type arg is c

  17.                        return c;

  18.                }

  19.            }

  20.        }

  21.        return null;

  22.    }

这里的逻辑是获得类 C ,然后获取它实现的接口 Comparable < C > ,然后从这个 Comparable < C > 中获得类型参数 C ,然后比较这两个类型是否相等。虽然我们一直听说Java的泛型是类型擦除式,但是在这里我们是可以获得泛型的参数类型的。照例用一段demo测试一下:

  1. public class ParameterApp {

  2.    public static void main( String[] args) {

  3.        StringList list = new StringList();

  4.        Class> clazz = getTypeArgument(list);

  5.        System.out.println(clazz.getName());

  6.    }

  7.    static Class> getTypeArgument(Object x) {

  8.        if (x instanceof Collection) {

  9.            Class> c = x.getClass();

  10.            Type[] ts, as; Type t; ParameterizedType p;

  11.            if ((ts = c.getGenericInterfaces()) != null) {

  12.                for (int i = 0; i < ts.length; ++i) {

  13.                    if (((t = ts[i]) instanceof ParameterizedType) &&

  14.                            ((as  = ((ParameterizedType)t).getActualTypeArguments()) != null)

  15.                             &&

  16.                            as.length == 1) // type arg is c

  17.                        return (Class>) as[0];

  18.                }

  19.            }

  20.        }

  21.        return null;

  22.    }

  23.    static class StringList extends AbstractList<String> implements List<String> {

  24.        @Override

  25.        public String get(int i) {

  26.            return null;

  27.        }

  28.        @Override

  29.         public int size() {

  30.            return 0;

  31.        }

  32.    }

  33. }

sun.reflect.Reflection

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

  1.    @CallerSensitive

  2.    public static native Class> getCallerClass();

我第一次见到这个方法是在 java . sql . DriverManager 中的 getConnection 方法中见到的:

  1.    @CallerSensitive

  2.    public static Connection getConnection(String url,

  3.        String user, String password) throws SQLException {

  4.        java .util.Properties info = new java.util.Properties();

  5.        if (user != null) {

  6.            info.put("user", user);

  7.        }

  8.        if (password != null) {

  9.            info.put("password", password);

  10.        }

  11.        return (getConnection(url, info, Reflection.getCallerClass()));

  12.    }

Reflection . getCallerClass () 是一个 native 方法,返回的是 Class > 类型,在 DriverManager 中使用它的目的是为了获得相应的 ClassLoader ,上面的代码是在Java 8中见到的。其中在Java 7中为获得 ClassLoader DriverManager 就直接提供了 native 的方法:

  1. /* Returns the caller's class loader, or null if none */

  2. private static native ClassLoader getCallerClassLoader();

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

  1. public class CalleeApp {

  2.    public void call() {

  3.        Class> clazz = Reflection.getCallerClass();

  4.        







请到「今天看啥」查看全文