• java获取全部子类或接口的全部实现


    在JAVA中,获取一个类的全部父类是比较简单的,只需要通过反射(Class的getSuperclass()方法)即可。然而,如果想获得一个类的所有子类,或者获得实现某一个接口的所有实现类,相对比较麻烦。

    用过Eclipse的开发人员都知道,通过F4键或(Ctrl+T组合键)可以查到指定类的类层次结构。仔细想一下该快捷键的实现原理,或许可以找到一个可行的设计思路。

    首先,需要确定一个前提是,寻找所有子类,必须先指定搜索的文件范围。打个比方,要寻找一个古人的所有后代成员,必须设置查找的地理范围是在中国内,否则就无从入手。

    结合实际的项目部署环境,查找子类的方法需要有两种方式。第一种,在开发环境,可以直接遍历指定范围下的所有源代码文件,再结合反射的知识;第二种,假设项目已经打成jar包,则只能通过jar包获得所有类文件。

    下面给出具体的代码实现

    1.若是开发环境,则通过递归查找指定目录下的类文件的全路径,代码如下

     1 /**
     2  * 递归查找指定目录下的类文件的全路径
     3  *
     4  * @param baseFile 查找文件的入口
     5  * @param fileList 保存已经查找到的文件集合
     6  */
     7 public static void getSubFileNameList(File baseFile, List<String> fileList) {
     8     if (baseFile.isDirectory()) {
     9         File[] files = baseFile.listFiles();
    10         for (File tmpFile : files) {
    11             getSubFileNameList(tmpFile, fileList);
    12         }
    13     }
    14     String path = baseFile.getPath();
    15     if (path.endsWith(".java")) {
    16         String name1 = path.substring(path.indexOf("src") + 4, path.length());
    17         String name2 = name1.replaceAll("\\", ".");
    18         String name3 = name2.substring(0, name2.lastIndexOf(".java"));
    19         fileList.add(name3);
    20     }
    21 }

    获取根路径方法 final static File rootFolder = new File(SuperClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());

    2.若是jar包环境,则可以通过JarFile这个工具类,获得所有全部类信息

     1 /**
     2  * 从jar包读取所有的class文件名
     3  */
     4 private static List<String> getClassNameFrom(String jarName) {
     5     List<String> fileList = new ArrayList<String>();
     6     try {
     7         JarFile jarFile = new JarFile(new File(jarName));
     8         Enumeration<JarEntry> en = jarFile.entries(); // 枚举获得JAR文件内的实体,即相对路径  
     9         while (en.hasMoreElements()) {
    10             String name1 = en.nextElement().getName();
    11             if (!name1.endsWith(".class")) {//不是class文件
    12                 continue;
    13             }
    14             String name2 = name1.substring(0, name1.lastIndexOf(".class"));
    15             String name3 = name2.replaceAll("/", ".");
    16             fileList.add(name3);
    17         }
    18     } catch (IOException e) {
    19         e.printStackTrace();
    20     }
    21 
    22     return fileList;
    23 }

    3.从前两步可以得到所有子类或所有接口实现类的类路径信息,有了类的全路径,就可以通过反射拿到类的信息,用来判断是否满足条件

     1 /**
     2  * 判断一个类是否继承某个父类或实现某个接口
     3  */
     4 public static boolean isChildClass(String className, Class parentClazz) {
     5     if (className == null) return false;
     6 
     7     Class clazz = null;
     8     try {
     9         clazz = Class.forName(className);
    10         if (Modifier.isAbstract(clazz.getModifiers())) {//抽象类忽略
    11             return false;
    12         }
    13         if (Modifier.isInterface(clazz.getModifiers())) {//接口忽略
    14             return false;
    15         }
    16     } catch (Exception e) {
    17         e.printStackTrace();
    18         return false;
    19     }
    20     return parentClazz.isAssignableFrom(clazz);
    21 
    22 }

    4.写几个简单的测试类,用来说明问题

    1 package bean;
    2 
    3 public abstract class Animal {
    4     public abstract void eat();
    5     public abstract void walk();
    6 }
     1 package bean;
     2  
     3 public class Cat extends Animal{
     4  
     5     @Override
     6     public void eat() {
     7         System.err.println("小猫吃东西");
     8     }
     9  
    10     @Override
    11     public void walk() {
    12         System.err.println("小猫走路");
    13     }
    14  
    15 }
     1 package bean;
     2  
     3 public class Dog extends Animal{
     4  
     5     @Override
     6     public void eat() {
     7         System.err.println("小狗吃东西");
     8     }
     9  
    10     @Override
    11     public void walk() {
    12         System.err.println("小狗走路");
    13     }
    14  
    15 }
     1 package bean;
     2  
     3 public class Person {
     4     private String name;
     5     private int age;
     6     
     7     public Person(){
     8         
     9     }
    10     public Person(String name, int age) {
    11         super();
    12         this.name = name;
    13         this.age = age;
    14     }
    15  
    16     public void sayHello(){
    17         System.err.println("hello,i am " + this.name);
    18     }
    19 }

    5.入口方法,打印输出结果(jar包可直接使用Eclipse导出可执行jar文件)

     1     List<String> fileList = new ArrayList<String>();
     2 
     3     File baseFile = new File(getSrcPath() + File.separator + "src" + File.separator + "bean");
     4         if(baseFile.exists()){//开发环境,读取源文件
     5                 getSubFileNameList(baseFile,fileList);
     6                 }else{//jar包环境
     7                 fileList=getClassNameFrom("server.jar");
     8                 }
     9                 System.err.println("Animal类的所有子类有");
    10                 for(String name:fileList){
    11                 if(isChildClass(name,Animal.class))
    12         System.err.println(name);
    13         }
  • 相关阅读:
    如何在一个项目中同时包含mvc建站、webapi接口
    解决api、WebService跨域问题
    mvc接口、webapi、webservice 对比
    云服务器 远程mysql 无法连接
    c#快速写本地日志
    使用筛选器特性标记方法解决webapi 跨域问题
    流量控制(滑动窗口协议)
    解释Windows7“上帝模式”的原理
    Linux网络协议栈(二)——套接字缓存(socket buffer)
    理解MySQL——架构与概念
  • 原文地址:https://www.cnblogs.com/linkenpark/p/11383355.html
Copyright © 2020-2023  润新知