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

通过Thread.currentThread().getContextClassLoader()获取ClassLoader实例
将包名转为路径名后,做为参数传给CloassLoader.getResources(),以得到该路径下所有资源的URL;
通过URL.getProtocol()方法,判断资源是在本地(file:)或是第三方jar包(jar:)内;
在本地的类直接文件遍历即可;
第三方jar则通过URL.openConnection()得到JarURLConnection,再通过JarURLConnection.getJarFile()获得JarFile,最后遍历该JarFile的item即可。

package lab.sodino.clazz;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* Annotation:见http://blog.csdn.net/sodino/article/details/7987888
* */
@Target(ElementType.TYPE)//ElementType.TYPE用于标识类、接口(包括内注自身)、枚举
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface author {
//修饰符仅可为public, protected, private & static的组合
public static enum AppEnum {
Web, Client, Service, Undesignated
}; //public & abstract的组合或默认
AppEnum type() default AppEnum.Undesignated; String name() default "unknown"; String webSite() default "N/A";
}
package lab.sodino.clazz;
/**
* @author Sodino E-mail:sodino@qq.com
* @version Time:2014年2月10日 下午9:06:55
*/
@author(name="sodino", webSite="sodino.com")
public class ClassTestDemo { }
package lab.sodino.clazz;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
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; /**
* 用于获取指定包名下的所有类名.<br/>
* 并可设置是否遍历该包名下的子包的类名.<br/>
* 并可通过Annotation(内注)来过滤,避免一些内部类的干扰.<br/>
*
* @author Sodino E-mail:sodino@qq.com
* @version Time:2014年2月10日 下午3:55:59
*/
public class ClassUtil {
public static void main(String []args){
// 标识是否要遍历该包路径下子包的类名
// boolean recursive = false;
boolean recursive = true;
// 指定的包名
// String pkg = "javax.crypto.spec";// 为java/jre6/lib/jce.jar,普通的java工程默认已引用
// String pkg = "javax.crypto";
// String pkg = "lab.sodino";
String pkg = "lab.sodino.clazz";
List list = null;
// list = getClassList(pkg, recursive, null);
// 增加 author.class的过滤项,即可只选出ClassTestDemo
list = getClassList(pkg, recursive, author.class); for(int i = 0;i < list.size(); i ++){
System.out.println(i +":"+list.get(i));
}
} public static List<Class<?>> getClassList(String pkgName , boolean isRecursive, Class<? extends Annotation> annotation) {
List<Class<?>> classList = new ArrayList<Class<?>>();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try {
// 按文件的形式去查找
String strFile = pkgName.replaceAll("\\.", "/");
Enumeration<URL> urls = loader.getResources(strFile);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url != null) {
String protocol = url.getProtocol();
String pkgPath = url.getPath();
System.out.println("protocol:" + protocol +" path:" + pkgPath);
if ("file".equals(protocol)) {
// 本地自己可见的代码
findClassName(classList, pkgName, pkgPath, isRecursive, annotation);
} else if ("jar".equals(protocol)) {
// 引用第三方jar的代码
findClassName(classList, pkgName, url, isRecursive, annotation);
}
}
}
} catch (IOException e) {
e.printStackTrace();
} return classList;
} public static void findClassName(List<Class<?>> clazzList, String pkgName, String pkgPath, boolean isRecursive, Class<? extends Annotation> annotation) {
if(clazzList == null){
return;
}
File[] files = filterClassFiles(pkgPath);// 过滤出.class文件及文件夹
System.out.println("files:" +((files == null)?"null" : "length=" + files.length));
if(files != null){
for (File f : files) {
String fileName = f.getName();
if (f.isFile()) {
// .class 文件的情况
String clazzName = getClassName(pkgName, fileName);
addClassName(clazzList, clazzName, annotation);
} else {
// 文件夹的情况
if(isRecursive){
// 需要继续查找该文件夹/包名下的类
String subPkgName = pkgName +"."+ fileName;
String subPkgPath = pkgPath +"/"+ fileName;
findClassName(clazzList, subPkgName, subPkgPath, true, annotation);
}
}
}
}
} /**
* 第三方Jar类库的引用。<br/>
* @throws IOException
* */
public static void findClassName(List<Class<?>> clazzList, String pkgName, URL url, boolean isRecursive, Class<? extends Annotation> annotation) throws IOException {
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
System.out.println("jarFile:" + jarFile.getName());
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String jarEntryName = jarEntry.getName(); // 类似:sun/security/internal/interfaces/TlsMasterSecret.class
String clazzName = jarEntryName.replace("/", ".");
int endIndex = clazzName.lastIndexOf(".");
String prefix = null;
if (endIndex > 0) {
String prefix_name = clazzName.substring(0, endIndex);
endIndex = prefix_name.lastIndexOf(".");
if(endIndex > 0){
prefix = prefix_name.substring(0, endIndex);
}
}
if (prefix != null && jarEntryName.endsWith(".class")) {
// System.out.println("prefix:" + prefix +" pkgName:" + pkgName);
if(prefix.equals(pkgName)){
System.out.println("jar entryName:" + jarEntryName);
addClassName(clazzList, clazzName, annotation);
} else if(isRecursive && prefix.startsWith(pkgName)){
// 遍历子包名:子类
System.out.println("jar entryName:" + jarEntryName +" isRecursive:" + isRecursive);
addClassName(clazzList, clazzName, annotation);
}
}
}
} private static File[] filterClassFiles(String pkgPath) {
if(pkgPath == null){
return null;
}
// 接收 .class 文件 或 类文件夹
return new File(pkgPath).listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
}
});
} private static String getClassName(String pkgName, String fileName) {
int endIndex = fileName.lastIndexOf(".");
String clazz = null;
if (endIndex >= 0) {
clazz = fileName.substring(0, endIndex);
}
String clazzName = null;
if (clazz != null) {
clazzName = pkgName + "." + clazz;
}
return clazzName;
} private static void addClassName(List<Class<?>> clazzList, String clazzName, Class<? extends Annotation> annotation) {
if (clazzList != null && clazzName != null) {
Class<?> clazz = null;
try {
clazz = Class.forName(clazzName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// System.out.println("isAnnotation=" + clazz.isAnnotation() +" author:" + clazz.isAnnotationPresent(author.class)); if (clazz != null) {
if(annotation == null){
clazzList.add(clazz);
System.out.println("add:" + clazz);
} else if (clazz.isAnnotationPresent(annotation)){
clazzList.add(clazz);
System.out.println("add annotation:" + clazz);
}
}
}
}
}

遍历指定包名下所有的类(支持jar)(转)的更多相关文章

  1. Java获取指定包名下的所有类的全类名的解决方案

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

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

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

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

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

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

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

  5. Java反射 - 1(得到类对象的几种方法,调用方法,得到包下的所有类)

    通过反射获得对象的方法 准备工作: 有一个User类如下 package o1; /** * Created by yesiming on 16-11-19. */ public class User ...

  6. java动态载入指定的类或者jar包反射调用其方法

    序言 有时候.项目中会用到java动态载入指定的类或者jar包反射调用其方法来达到模块的分离,使各个功能之间耦合性大大减少,更加的模块化.代码利用率更高.模式中的代理模式就用到java的这一机制. 下 ...

  7. java 查找指定包下的类

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

  8. 黑马程序员——【Java基础】——File类、Properties集合、IO包中的其他类

    ---------- android培训.java培训.期待与您交流! ---------- 一.File类 (一)概述 1.File类:文件和目录路径名的抽象表现形式 2.作用: (1)用来将文件或 ...

  9. 代码片段:基于 JDK 8 time包的时间工具类 TimeUtil

    摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! “知识的工作者必须成为自己时间的首席执行官.” 前言 这次泥瓦匠带来的是一个好玩的基于 JDK ...

随机推荐

  1. cocos2d-x游戏开发系列教程-坦克大战游戏之虚拟手柄的显示

    上篇文章我们有了坦克,但是没有手柄,无法控制坦克. 1.这篇我们编写虚拟手柄来控制坦克.头文件大致内容如下: #define RES_PADDLE_LEFT "paddle/left.png ...

  2. 基于visual Studio2013解决C语言竞赛题之1017次数

         题目 解决代码及点评 /* 功能:有人说在400, 401, 402, ...499这些数中4这个数字共出现112次,请编程序判定这 种说法是否正确.若正确请打印出'YE ...

  3. ajax终结篇

    Ajax中post和get的区别 在ajax中有这个方法 xmlreq.open("post","servlet/MyServlet?time="+newDat ...

  4. 【学习opencv第六篇】图像的反转操作

    考试终于完了,现在终于有时间可以继续学习这个了.写这篇博客主要是因为以前一直搞不清楚图像数据到底是怎么存储的,以及这个step到底是什么,后来查了一下才知道原来step就是数据行的长度.. #incl ...

  5. 在Android手机上获取其它应用的包名及版本

    转载请注明出处:http://blog.csdn.net/jason_src/article/details/37757661 获取Android手机上其它应用的包名及版本方法有非常多,能够通过AAP ...

  6. Spring Mobile是如何判断访问设备的类型的

    Spring最近换域名了,去转转,发现了一个有意思的项目:spring mobile. http://projects.spring.io/spring-mobile/ 这个项目有很多实用的功能,如识 ...

  7. event.srcElement获得引发事件的控件(表单)

    <1> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...

  8. Tomcat 用户配置

    如果你没有改变任何配置文件,请检查文件conf / tomcat用户.xml在你安装.该文件必须包含凭证让你使用这个应用. 例如,添加一个用户名为tomcat manager gui角色s3cret密 ...

  9. Hive HA使用说明

    hive让大数据飞了起来,不再需要专人写MR.平常我们都可以用基于thrift的任意语言来调用hive. 不过爱恨各半,hive的thrift不稳定也是出了名的.很容易就出问题,让人无计可施.唯一的办 ...

  10. boost.asio包装类st_asio_wrapper开发教程(2014.5.23更新)(一)-----转

    一:什么是st_asio_wrapper它是一个c/s网络编程框架,基于对boost.asio的包装(最低在boost-1.49.0上调试过),目的是快速的构建一个c/s系统: 二:st_asio_w ...