Java/Kotlin中区分不同模块的同名全限定名类
嘿,这个问题问到点子上了!当两个不同模块里出现全限定名完全相同的类(比如你说的module-one和module-two里的io.foo.Bar)时,getQualifiedName()确实会返回一模一样的字符串,但Java其实提供了几种绝对可靠的区分方式,我给你逐一说明:
1. 直接对比Class对象本身
在Java的类模型里,一个类的唯一性由「全限定名 + 类加载器 + 所属模块(Java 9+)」共同决定。哪怕两个类的全限定名完全一致,只要它们来自不同模块或者由不同类加载器加载,它们的Class对象就是完全不同的实例。所以直接用==比较两个Class对象就能区分:
Class<?> barFromModule1 = ...; // 来自module-one的Bar类对象 Class<?> barFromModule2 = ...; // 来自module-two的Bar类对象 boolean areDifferentClasses = barFromModule1 != barFromModule2; // 这里会返回true,因为它们是不同的类实例
2. 获取类所属的模块信息(Java 9+ 推荐方式)
这是模块系统专门为这类场景设计的解决方案。每个类都属于一个明确的模块,调用Class.getModule()就能拿到对应的Module对象,通过模块名可以直接区分:
// 获取模块名 String moduleName1 = barFromModule1.getModule().getName(); String moduleName2 = barFromModule2.getModule().getName(); // 直接对比模块名即可确定来源 boolean fromSameModule = moduleName1.equals(moduleName2); // 返回false
除了模块名,你还可以通过Module.getDescriptor()获取模块的详细描述信息,比如模块的依赖、导出包等,进一步验证类的来源。
3. 对比类加载器
每个类都是由特定的类加载器加载的,不同模块的类通常由不同的类加载器(或类加载器层级中的不同节点)加载。你可以通过Class.getClassLoader()获取加载该类的类加载器,然后对比加载器实例:
ClassLoader loader1 = barFromModule1.getClassLoader(); ClassLoader loader2 = barFromModule2.getClassLoader(); boolean loadedBySameLoader = loader1 == loader2; // 在大多数模块场景下,这里会返回false
不过要注意:如果两个模块是由同一个类加载器加载的(这种情况比较少见),这个方法就不如对比模块信息可靠,所以优先推荐第二种方式。
总结一下,最简洁且可靠的区分方式就是获取类的模块信息,或者直接对比Class对象本身——这两种方法都能100%区分不同模块中的同名同包类。
内容的提问来源于stack exchange,提问作者Matthew Layton

