我之前使用Reflections库来查找Java中给定类的所有子类。
这是我在简单java 项目中使用的代码段:
Reflections reflections = new Reflections(PACKAGE_NAME);
Set<Class<? extends SuperClass>> subTypes =
reflections.getSubTypesOf(SuperClass.class);
for (Class<? extends SuperClass> subType : subTypes) {
log("Subclass = " + subType.getSimpleName());
}
当我在 android 项目中运行相同的代码时,“subType”List返回空。
任何人都可以帮我在Android上完成这项工作吗?
修改 我为整个工作添加的罐子是:
答案 0 :(得分:1)
也许你可以试试这个:
public abstract class ClassScanner {
private static final String TAG = "ClassScanner";
private Context mContext;
public ClassScanner(Context context) {
mContext = context;
}
public Context getContext() {
return mContext;
}
void scan() throws IOException, ClassNotFoundException, NoSuchMethodException {
long timeBegin = System.currentTimeMillis();
PathClassLoader classLoader = (PathClassLoader) getContext().getClassLoader();
//PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();//This also works good
DexFile dexFile = new DexFile(getContext().getPackageCodePath());
Enumeration<String> classNames = dexFile.entries();
while (classNames.hasMoreElements()) {
String className = classNames.nextElement();
if (isTargetClassName(className)) {
//Class<?> aClass = Class.forName(className);//java.lang.ExceptionInInitializerError
//Class<?> aClass = Class.forName(className, false, classLoader);//tested on 魅蓝Note(M463C)_Android4.4.4 and Mi2s_Android5.1.1
Class<?> aClass = classLoader.loadClass(className);//tested on 魅蓝Note(M463C)_Android4.4.4 and Mi2s_Android5.1.1
if (isTargetClass(aClass)) {
onScanResult(aClass);
}
}
}
long timeEnd = System.currentTimeMillis();
long timeElapsed = timeEnd - timeBegin;
Log.d(TAG, "scan() cost " + timeElapsed + "ms");
}
protected abstract boolean isTargetClassName(String className);
protected abstract boolean isTargetClass(Class clazz);
protected abstract void onScanResult(Class clazz);
}
这是一个如何使用的例子:
new ClassScanner(context) {
@Override
protected boolean isTargetClassName(String className) {
return className.startsWith(getContext().getPackageName())//I want classes under my package
&& !className.contains("$");//I don't need none-static inner classes
}
@Override
protected boolean isTargetClass(Class clazz) {
return AbsFactory.class.isAssignableFrom(clazz)//I want subclasses of AbsFactory
&& !Modifier.isAbstract(clazz.getModifiers());//I don't want abstract classes
}
@Override
protected void onScanResult(Class clazz) {
Constructor constructor = null;
try {
constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
constructor.newInstance();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}.scan();
答案 1 :(得分:0)
由于Android中使用的编译过程,这可能无效。使用Java编译器将源代码转换为.class文件。下一步将.class文件转换为Android .dex文件(Dalvik字节码),它们不太可能保留所有元数据。
答案 2 :(得分:0)
有一个处理dex文件的官方API。有关详细信息,请参阅here。基本上,给定.dex文件的路径,您可以枚举其中的所有文件。要获取classes.dex
的网址,您可以使用
Thread.currentThread().getContextClassLoader().getResource("classes.dex")
(您可能需要剪切尾随"!/classes.dex"
,现在无法检查)。然后,您可以迭代classes.dex内容并尝试加载您以这种方式找到的所有类。 (Class.forName
),最后,检查您需要的任何类属性。但请注意,classes.dex
包含所有类,而“all”可能“非常多”。处理.dex文件时还需要记住其他性能问题。但是,只要你不尝试一些不必要的低效率,你就应该没事。特别是因为我以类似的方式完成了它的魔力,就我而言。
答案 3 :(得分:0)
这是基于fantouch答案的单方法解决方案。
结果也将包含不正确的后代。
public class Utils
{
// ...
public static ArrayList<Class> GetSubClasses( Context context, String packageName, Class targetSuperClass )
{
ArrayList<Class> subClasses = new ArrayList<>();
try
{
DexFile dex = new DexFile( context.getPackageCodePath() );
for ( Enumeration<String> iterator = dex.entries(); iterator.hasMoreElements(); )
{
String className = iterator.nextElement();
if ( !className.startsWith( packageName ) || className.contains("$") )
{
continue;
}
Class classObj = Class.forName( className );
Class superClass = classObj;
while ( true )
{
superClass = superClass.getSuperclass();
if ( superClass == null || superClass == Object.class )
{
break;
}
if ( superClass == targetSuperClass )
{
subClasses.add( classObj );
break;
}
}
}
}
catch ( Exception e )
{
e.printStackTrace();
}
return subClasses;
}
}