最近有个需求需要获取一个指定包下的所有类的全类名,因此特意写了个获取指定包下所有类的全类名的工具类。在此记录一下,方便后续查阅

一、思路

        通过ClassLoader来查找指定包,如果是在classes文件夹下的class文件,则用遍历文件的方式来获取该包下的所有类名。如果这个包名是jar包里面的,那么需要通过遍历jar包内文件的方式来获取该包下的所有类的类名

二、代码

       代码如下
package com.zxy.demo.common.utils;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile; /**
* ClazzUtils
* @author ZENG.XIAO.YAN
* @version 1.0
*/
public class ClazzUtils {
private static final String CLASS_SUFFIX = ".class";
private static final String CLASS_FILE_PREFIX = File.separator + "classes" + File.separator;
private static final String PACKAGE_SEPARATOR = "."; /**
* 查找包下的所有类的名字
* @param packageName
* @param showChildPackageFlag 是否需要显示子包内容
* @return List集合,内容为类的全名
*/
public static List<String> getClazzName(String packageName, boolean showChildPackageFlag ) {
List<String> result = new ArrayList<>();
String suffixPath = packageName.replaceAll("\\.", "/");
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try {
Enumeration<URL> urls = loader.getResources(suffixPath);
while(urls.hasMoreElements()) {
URL url = urls.nextElement();
if(url != null) {
String protocol = url.getProtocol();
if("file".equals(protocol)) {
String path = url.getPath();
System.out.println(path);
result.addAll(getAllClassNameByFile(new File(path), showChildPackageFlag));
} else if("jar".equals(protocol)) {
JarFile jarFile = null;
try{
jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
} catch(Exception e){
e.printStackTrace();
}
if(jarFile != null) {
result.addAll(getAllClassNameByJar(jarFile, packageName, showChildPackageFlag));
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
} /**
* 递归获取所有class文件的名字
* @param file
* @param flag 是否需要迭代遍历
* @return List
*/
private static List<String> getAllClassNameByFile(File file, boolean flag) {
List<String> result = new ArrayList<>();
if(!file.exists()) {
return result;
}
if(file.isFile()) {
String path = file.getPath();
// 注意:这里替换文件分割符要用replace。因为replaceAll里面的参数是正则表达式,而windows环境中File.separator="\\"的,因此会有问题
if(path.endsWith(CLASS_SUFFIX)) {
path = path.replace(CLASS_SUFFIX, "");
// 从"/classes/"后面开始截取
String clazzName = path.substring(path.indexOf(CLASS_FILE_PREFIX) + CLASS_FILE_PREFIX.length())
.replace(File.separator, PACKAGE_SEPARATOR);
if(-1 == clazzName.indexOf("$")) {
result.add(clazzName);
}
}
return result; } else {
File[] listFiles = file.listFiles();
if(listFiles != null && listFiles.length > 0) {
for (File f : listFiles) {
if(flag) {
result.addAll(getAllClassNameByFile(f, flag));
} else {
if(f.isFile()){
String path = f.getPath();
if(path.endsWith(CLASS_SUFFIX)) {
path = path.replace(CLASS_SUFFIX, "");
// 从"/classes/"后面开始截取
String clazzName = path.substring(path.indexOf(CLASS_FILE_PREFIX) + CLASS_FILE_PREFIX.length())
.replace(File.separator, PACKAGE_SEPARATOR);
if(-1 == clazzName.indexOf("$")) {
result.add(clazzName);
}
}
}
}
}
}
return result;
}
} /**
* 递归获取jar所有class文件的名字
* @param jarFile
* @param packageName 包名
* @param flag 是否需要迭代遍历
* @return List
*/
private static List<String> getAllClassNameByJar(JarFile jarFile, String packageName, boolean flag) {
List<String> result = new ArrayList<>();
Enumeration<JarEntry> entries = jarFile.entries();
while(entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
String name = jarEntry.getName();
// 判断是不是class文件
if(name.endsWith(CLASS_SUFFIX)) {
name = name.replace(CLASS_SUFFIX, "").replace("/", ".");
if(flag) {
// 如果要子包的文件,那么就只要开头相同且不是内部类就ok
if(name.startsWith(packageName) && -1 == name.indexOf("$")) {
result.add(name);
}
} else {
// 如果不要子包的文件,那么就必须保证最后一个"."之前的字符串和包名一样且不是内部类
if(packageName.equals(name.substring(0, name.lastIndexOf("."))) && -1 == name.indexOf("$")) {
result.add(name);
}
}
}
}
return result;
} public static void main(String[] args) {
List<String> list = ClazzUtils.getClazzName("com.mysql.fabric", false);
for (String string : list) {
System.out.println(string);
}
}
}
 
1
package com.zxy.demo.common.utils;
2
import java.io.File;
3
import java.io.IOException;
4
import java.net.JarURLConnection;
5
import java.net.URL;
6
import java.util.ArrayList;
7
import java.util.Enumeration;
8
import java.util.List;
9
import java.util.jar.JarEntry;
10
import java.util.jar.JarFile;
11

12
/**
13
 * ClazzUtils
14
 * @author ZENG.XIAO.YAN
15
 * @version 1.0
16
 */
17
public class ClazzUtils {
18
    private static final String CLASS_SUFFIX = ".class";
19
    private static final String CLASS_FILE_PREFIX = File.separator + "classes"  + File.separator;
20
    private static final String PACKAGE_SEPARATOR = ".";
21
    
22
    
23
    
24
    
25
    /**
26
     * 查找包下的所有类的名字
27
     * @param packageName
28
     * @param showChildPackageFlag 是否需要显示子包内容
29
     * @return List集合,内容为类的全名
30
     */
31
    public static List<String> getClazzName(String packageName, boolean showChildPackageFlag ) {
32
        List<String> result = new ArrayList<>();
33
        String suffixPath = packageName.replaceAll("\\.", "/");
34
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
35
        try {
36
            Enumeration<URL> urls = loader.getResources(suffixPath);
37
            while(urls.hasMoreElements()) {
38
                URL url = urls.nextElement();
39
                if(url != null) {
40
                    String protocol = url.getProtocol();
41
                    if("file".equals(protocol)) {
42
                        String path = url.getPath();
43
                        System.out.println(path);
44
                        result.addAll(getAllClassNameByFile(new File(path), showChildPackageFlag));
45
                    } else if("jar".equals(protocol)) {
46
                        JarFile jarFile = null;
47
                        try{
48
                            jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
49
                        } catch(Exception e){
50
                            e.printStackTrace();
51
                        }
52
                        if(jarFile != null) {
53
                            result.addAll(getAllClassNameByJar(jarFile, packageName, showChildPackageFlag));
54
                        }
55
                    }
56
                }
57
            }
58
        } catch (IOException e) {
59
            e.printStackTrace();
60
        }
61
        return result;
62
    }
63
    
64
    
65
    /**
66
     * 递归获取所有class文件的名字
67
     * @param file 
68
     * @param flag  是否需要迭代遍历
69
     * @return List
70
     */
71
    private static List<String> getAllClassNameByFile(File file, boolean flag) {
72
        List<String> result =  new ArrayList<>();
73
        if(!file.exists()) {
74
            return result;
75
        }
76
        if(file.isFile()) {
77
            String path = file.getPath();
78
            // 注意:这里替换文件分割符要用replace。因为replaceAll里面的参数是正则表达式,而windows环境中File.separator="\\"的,因此会有问题
79
            if(path.endsWith(CLASS_SUFFIX)) {
80
                path = path.replace(CLASS_SUFFIX, "");
81
                // 从"/classes/"后面开始截取
82
                String clazzName = path.substring(path.indexOf(CLASS_FILE_PREFIX) + CLASS_FILE_PREFIX.length())
83
                        .replace(File.separator, PACKAGE_SEPARATOR);
84
                if(-1 == clazzName.indexOf("$")) {
85
                    result.add(clazzName);
86
                }
87
            }
88
            return result;
89
            
90
        } else {
91
            File[] listFiles = file.listFiles();
92
            if(listFiles != null && listFiles.length > 0) {
93
                for (File f : listFiles) {
94
                    if(flag) {
95
                        result.addAll(getAllClassNameByFile(f, flag));
96
                    } else {
97
                        if(f.isFile()){
98
                            String path = f.getPath();
99
                            if(path.endsWith(CLASS_SUFFIX)) {
100
                                path = path.replace(CLASS_SUFFIX, "");
101
                                // 从"/classes/"后面开始截取
102
                                String clazzName = path.substring(path.indexOf(CLASS_FILE_PREFIX) + CLASS_FILE_PREFIX.length())
103
                                        .replace(File.separator, PACKAGE_SEPARATOR);
104
                                if(-1 == clazzName.indexOf("$")) {
105
                                    result.add(clazzName);
106
                                }
107
                            }
108
                        }
109
                    }
110
                }
111
            } 
112
            return result;
113
        }
114
    }
115
    
116
    
117
    /**
118
     * 递归获取jar所有class文件的名字
119
     * @param jarFile 
120
     * @param packageName 包名
121
     * @param flag  是否需要迭代遍历
122
     * @return List
123
     */
124
    private static List<String> getAllClassNameByJar(JarFile jarFile, String packageName, boolean flag) {
125
        List<String> result =  new ArrayList<>();
126
        Enumeration<JarEntry> entries = jarFile.entries();
127
        while(entries.hasMoreElements()) {
128
            JarEntry jarEntry = entries.nextElement();
129
            String name = jarEntry.getName();
130
            // 判断是不是class文件
131
            if(name.endsWith(CLASS_SUFFIX)) {
132
                name = name.replace(CLASS_SUFFIX, "").replace("/", ".");
133
                if(flag) {
134
                    // 如果要子包的文件,那么就只要开头相同且不是内部类就ok
135
                    if(name.startsWith(packageName) && -1 == name.indexOf("$")) {
136
                        result.add(name);
137
                    }
138
                } else {
139
                    // 如果不要子包的文件,那么就必须保证最后一个"."之前的字符串和包名一样且不是内部类
140
                    if(packageName.equals(name.substring(0, name.lastIndexOf("."))) && -1 == name.indexOf("$")) {
141
                        result.add(name);
142
                    }
143
                }
144
            }
145
        }
146
        return result;
147
    }
148
    
149
    public static void main(String[] args) {
150
        List<String> list = ClazzUtils.getClazzName("com.mysql.fabric", false);
151
        for (String string : list) {
152
            System.out.println(string);
153
        }
154
    }
155
}
156

三、小结

        (1)写代码时,注意String类的replace方法和replaceAll方法的区别
        (2)内部类生成的class文件有有美元符号"$"

Java获取指定包名下的所有类的全类名的解决方案的更多相关文章

  1. Java 获取指定包下的所有类

    package com.s.rest.util; import java.io.File; import java.io.FileFilter; import java.io.IOException; ...

  2. 遍历指定包名下所有的类(支持jar)(转)

    支持包名下的子包名遍历,并使用Annotation(内注)来过滤一些不必要的内部类,提高命中精度. 通过Thread.currentThread().getContextClassLoader()获取 ...

  3. Java -- 获取指定接口的所有实现类或获取指定类的所有继承类

    Class : ClassUtil package pri.lime.main; import java.io.File; import java.io.IOException; import jav ...

  4. 获取指定包名下继承或者实现某接口的所有类(扫描文件目录和所有jar)

    import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.JarURLCo ...

  5. Android支持Split Apks后,如何获得指定包名下的所有类

    从Android5.0以后,支持多个apk动态部署,这导致以前通过单一apk获取包路径下的所有类的方法失效,不过稍微修改一下原先的代码就可以,代码如下 public static final List ...

  6. java.util.regex包下的Pattern类和Matcher类的使用总结

    一.介绍 Java正则表达式通过java.util.regex包下的Pattern类与Matcher类实现1.Pattern类用于创建一个正则表达式,也可以说创建一个匹配模式,它的构造方法是私有的,不 ...

  7. C#获取指定IP地址的数据库所有数据库实例名

    /// <summary> /// 获取指定IP地址的数据库所有数据库实例名. /// </summary> /// <param name="ip" ...

  8. java 查找指定包下的类

    package com.jason.test; import java.io.File; import java.io.IOException; import java.io.UnsupportedE ...

  9. 24.Java中atomic包中的原子操作类总结

    1. 原子操作类介绍 在并发编程中很容易出现并发安全的问题,有一个很简单的例子就是多线程更新变量i=1,比如多个线程执行i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过Synchr ...

随机推荐

  1. ARP协议总结

    1.ARP用于实现ip和MAC地址之间的对应关系. 2.ARP的流程主要分为ARP请求.ARP应答.免费ARP. 3.首次ARP请求是广播报文,后续确认的ARP是单播报文. 4.免费ARP有两个用途, ...

  2. recovery 根据@/cache/recovery/block.map描述从data分区升级

    随着android版本的更新,系统固件的大小也越来越大,升级包也越来越大,cache分区已经不够存储update.zip了,所以应用把update.zip下载到data分区,默认情况下data分区是可 ...

  3. 机器学习实战(Machine Learning in Action)学习笔记————10.奇异值分解(SVD)原理、基于协同过滤的推荐引擎、数据降维

    关键字:SVD.奇异值分解.降维.基于协同过滤的推荐引擎作者:米仓山下时间:2018-11-3机器学习实战(Machine Learning in Action,@author: Peter Harr ...

  4. AIOps 一场颠覆传统运维的盛筵

    "颠覆传统运维."是 OneAPM CEO 陈旭经常挂在嘴边的一句话.为什么说 AIOps 将颠覆传统运维?如何才能把人工智能和运维管理相结合并落地? 2018年5月,OneAPM ...

  5. JMeter—系统性能分析思路(十三)

    参考<全栈性能测试修炼宝典JMeter实战>第九章 性能监控诊断 第二节 系统性能分析思路和第三节 定位分析 系统在工作负载中的性能受到许多因素影响,处理器速度.内存容量.网络或磁盘I/O ...

  6. tkinter做一个简单的登陆页面(十六)

    做一个简单的登陆页面 import tkinter wuya = tkinter.Tk() wuya.title("wuya") wuya.geometry("900x3 ...

  7. Sql Server中查询当天,最近三天,本周,本月,最近一个月,本季度的数据的sql语句

    --当天: --最近三天: --本周: select * from T_news WHERE (DATEPART(wk, addtime) = DATEPART(wk, GETDATE())) AND ...

  8. Asp.net Mvc、webApi配置允许跨域

    Web.config 下<system.webServer> 节点下配置 <httpProtocol> <customHeaders> <add name=& ...

  9. January 04th, 2018 Week 01st Thursday

    Just do what works for you, because there will always be someone who think differently. 就做你自己所能做的,因为 ...

  10. Django templates 模板的语法

    MVC 以及 MTV MVC: M : model -->> 存取数据(模型) V: view -->> 信息的展示(视图) C: controller -->> ...