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

一、思路

        通过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. Java数据解析---JSON

    一.Java数据解析分为:XML解析和JSON解析 XML解析即是对XML文件中的数据解析,而JSON解析即对规定形式的数据解析,比XML解析更加方便 JSON解析基于两种结构: 1.键值对类型 { ...

  2. 【转】对cocos2d 之autorelease\ratain\release的理解

    原文链接:http://blog.sina.com.cn/s/blog_4057ab6201018y4y.html Objective C内存管理进阶(二):理解autorelease: http:/ ...

  3. Asp.Net Core 使用Quartz基于界面画接口管理做定时任务

    今天抽出一点点时间来造一个小轮子,是关于定时任务这块的. 这篇文章主要从一下几点介绍: 创建数据库管理表 创建web项目 引入quarzt nuget 包 写具体配置操作,实现定时任务处理 第一步:创 ...

  4. flask中的url_for的使用

    有多个路由的程序需要连接不同的网页链接,例如导航条 模板中构建正确的动态url较为困难,如果重定义路由,模板中的链接失效 url_for()函数: 使用url映射中保存的信息生成url 用法: 用视图 ...

  5. macos 下安装brew

    1.终端执行 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master ...

  6. Appium学习——安装Android SDK

    .下载Android SDK 下载地址:http://tools.android-studio.org/index.php/sdk 百度搜索Android SDK也可以. 下载之后,Android S ...

  7. 使用linq语句进行联表查询

    假设你有一个父表(例如:汽车),其关联一个子表,例如轮子(一对多).现在你想对于所有的父表汽车,遍历所有汽车,然后打印出来所有轮子的信息.默认的做法将是: SELECT CarId FROM Cars ...

  8. 手动将经典 VM 从 VHD 迁移到新的 ARM 托管磁盘 VM

    本部分有助于将现有 Azure VM 从经典部署模型迁移到资源管理器部署模型中的托管磁盘. 计划迁移到托管磁盘 本部分可帮助你针对 VM 和磁盘类型做出最佳决策. 位置 选取 Azure 托管磁盘可用 ...

  9. Unable to load DLL 'SQLite.Interop.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

    在主工程(ASP.NET WEB/WCF等)的NuGet里引用 System.Data.SQLite.Core 不仅仅是Service需要引用,主工程即使不直接使用SQLite的库,也需要引用. 若使 ...

  10. python第一百零五天 ---Django 基础 路由系统 URL 模板语言 ORM 操作

    一 路由系统 URL 1 url(r'^index/',views.index) url(r'^home/', views.Home.as_view()) 2 url(r'^detail-(\d+). ...