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

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

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

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

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

下面给出具体的代码实现

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

/**
	 *  递归查找指定目录下的类文件的全路径
	 * @param baseFile 查找文件的入口
	 * @param fileList 保存已经查找到的文件集合
	 */
	public static  void getSubFileNameList(File baseFile, List fileList){
		if(baseFile.isDirectory()){
			File[] files = baseFile.listFiles();
			for(File tmpFile : files){
				getSubFileNameList(tmpFile,fileList);
			}
		}
		String path = baseFile.getPath();
		if(path.endsWith(".java")){
			String name1 = path.substring(path.indexOf("src")+4, path.length());
			String name2 = name1.replaceAll("\\\\", ".");
			String name3 = name2.substring(0, name2.lastIndexOf(".java"));
			fileList.add(name3);
		}
	}
2.若是jar包环境,则可以通过JarFile这个工具类,获得所有全部类信息
/**
	 *  从jar包读取所有的class文件名
	 */
	private static List getClassNameFrom(String jarName){
		List fileList = new ArrayList();
		try {
			JarFile jarFile = new JarFile(new File(jarName));
			 Enumeration en = jarFile.entries(); // 枚举获得JAR文件内的实体,即相对路径  
			 while (en.hasMoreElements()) {
				 String name1 =  en.nextElement().getName();
				 if(!name1.endsWith(".class")){//不是class文件
					 continue;
				 }
				 String name2 = name1.substring(0, name1.lastIndexOf(".class"));
				 String name3 = name2.replaceAll("/", ".");
				 fileList.add(name3);
			 }
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return fileList;
	}

3.从前两步可以得到所有子类或所有接口实现类的类路径信息,有了类的全路径,就可以通过反射拿到类的信息,用来判断是否满足条件
/**
	 *  判断一个类是否继承某个父类或实现某个接口
	 */
	public static boolean isChildClass(String className,Class parentClazz){
		if(className == null) return false;
		
		Class clazz = null;
		try {
			clazz = Class.forName(className);
			if(Modifier.isAbstract(clazz.getModifiers())){//抽象类忽略
				return false;
			}
			if(Modifier.isInterface(clazz.getModifiers())){//接口忽略
				return false;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return parentClazz.isAssignableFrom(clazz);
		
	}

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

public abstract class Animal {

	public abstract void eat();
	
	public abstract void walk();
}
package bean;

public class Cat extends Animal{

	@Override
	public void eat() {
		System.err.println("小猫吃东西");
	}

	@Override
	public void walk() {
		System.err.println("小猫走路");
	}

}
package bean;

public class Dog extends Animal{

	@Override
	public void eat() {
		System.err.println("小狗吃东西");
	}

	@Override
	public void walk() {
		System.err.println("小狗走路");
	}

}
package bean;

public class Person {
	private String name;
	private int age;
	
	public Person(){
		
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public void sayHello(){
		System.err.println("hello,i am " + this.name);
	}
}
5.入口方法,打印输出结果(jar包可直接使用Eclipse导出可执行jar文件)
	List fileList = new ArrayList();
		
		File baseFile = new File(getSrcPath()+File.separator+"src"+File.separator+"bean");
		if(baseFile.exists()){//开发环境,读取源文件
			getSubFileNameList(baseFile,fileList);
		}else{//jar包环境
			fileList = getClassNameFrom("server.jar");
		}
		System.err.println("Animal类的所有子类有");
		for(String name:fileList){
			if(isChildClass(name, Animal.class))
			System.err.println(name);
		}
6.代码运行结果如下



7.获得一个类的全部父类,代码比较简单,如下

	public static void main(String[] args) {
		Class clazz = Cat.class;
		while(clazz != null){
			System.err.println(clazz.getName());
			clazz = clazz.getSuperclass();
		}
	}


你可能感兴趣的:(java)