Keary's Blog

【转载】Java 8系列之重新认识HashMap

摘要

HashMap是Java程序员使用频率最高的用于映射(键值对)处理的数据类型。随着JDK(Java Developmet Kit)版本的更新,JDK1.8对HashMap底层的实现进行了优化,例如引入红黑树的数据结构和扩容的优化等。本文结合JDK1.7和JDK1.8的区别,深入探讨HashMap的结构实现和功能原理。

简介

Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMap、Hashtable、LinkedHashMap和TreeMap,类继承关系如下图所示:
map1.png

动态Java类的加载与重加载

有时候我们在动态加载Java类后,可能需要在运行期间变更Class文件的内容,例如新增一个函数或成员变量等,然后重新加载这个Class文件,并实例化新的对象供使用。
一个典型的场景就是热部署。即系统有部分模板由于变更频繁,因此以Class文件的形式保存在DB、网络或文件系统内。当Class发生变更时,希望无需重新部署应用,就能重新加载新的Class。

ClassLoader基本介绍

ClassLoader是Java提供的一个动态加载Class的类,
想深入了解该类的原理和使用,可以参考这篇文章:深入探讨Java类加载器

一个简单的通过ClassLoader加载类的代码如下:

public class DemoLoader {
    
    public static void main(String[] args) throws ClassNotFoundException {
        // 获取指定类的加载器
        ClassLoader classLoader = DemoLoader.class.getClassLoader();    
        // 加载Class
        Class<?> clazz = classLoader.loadClass("com.demo.MyTestClass");
        // 实例化对象
        MyTestClass obj = clazz.newInstance();
    }
    
}

Java代码动态编译遇到的问题与解决

上一篇博文“动态编译Java代码并加载运行”给出了一个动态编译Java代码的范例,
这段代码本身是没问题的,
但是在实际运行过程中却无法使用,
最后排查了一阵子后才解决,
现在分享一下解决流程。

获取JavaCompiler返回NULL

动态编译Java代码时,第一句话就是调用ToolProvider的静态方法,获取JavaCompiler对象:

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

但是实际运行的时候发现,其返回值总是NULL。
查看getSystemJavaCompiler()方法,可以看到这一段代码:

private static final String[] defaultToolsLocation = { "lib", "tools.jar" };

File file = new File(System.getProperty("java.home"));
if (file.getName().equalsIgnoreCase("jre"))
    file = file.getParentFile();
for (String name : defaultToolsLocation)
    file = new File(file, name);

if (!file.exists())
    throw e;

动态编译Java代码并加载运行

最近学习了一些Java代码的动态编译和加载方法,
然后自己写了一个Example分享出来。

重新开始写博客

近几年都没好好写博客了,
也确实没什么东西可以写…

现在开始会把一些所学到的技术分享出来,
至于以前的文章已经归档到http://keary.cn/wp内。