java - 通过反射不断迭代字段的字段

标签 java android reflection android-reflection

请避免仅使用 Kotlin 和 Android 21 更高版本给出答案。

我正在尝试构建一个 API 解析器,它利用类层次结构逻辑来表示 API 层次结构本身。通过这种结构,我能够以一种简单的方式解析 API,而且我已经实现了这一点,但我想进一步改进它。

我将开始解释我已经实现的内容。

这是我的应用程序将通过 GET 接收、在内部解析和分派(dispatch)的示例 URL:

http://www.example.com/news/article/1105

在应用程序中,基本域是无关紧要的,但接下来的是 API 结构。

在这种情况下,我们混合了命令和变量:

  • 新闻(命令)
  • 文章(命令)
  • 1105(变量)

为了确定什么是命令,什么是变量,我构建了以下类结构:

public class API {
    public static final News extends AbstractNews {}
}

public class AbstractNews {
    public static final Article extends AbstractArticle {}
}

public class Article {
    public static void GET(String articleId) {
        // ...
    }
}

在分割 URL 后,我会迭代每个类,同时将每个命令与从 API 类开始的每个类(或子类)进行匹配。在到达分割 URL 的末尾之前,任何失败的匹配都会作为变量存储在单独的列表中。

对于上面提供的示例,流程如下:

将 URL 拆分为每个正斜杠(忽略基本域)

/news/article/1105

List<String> stringList = [
    news, 
    article,
    1105
];

迭代分割列表中的每个项目并再次匹配API结构化类(以下只是一个示例示例,它不是我当前实现的100%):

List<String> variableList = new ArrayList<>();
Class lastClass = API.class;

for (String stringItem : stringList) {

    if ((lastClass = classHasSubClass(lastClass, stringItem)) != null) {
        continue;
    }

    variableList.add(stringItem);

}

到达列表末尾后,我检查最后一个类是否包含请求方法(在本例中为 GET)并与变量列表一起调用。

正如我之前所说,这工作得很好,但它使每个类都直接暴露,因此参与该项目的任何其他人都可以直接且错误地访问它们,因此我试图使层次结构更加包含。

我也希望保留通过层次结构访问方法的能力,因此仍然可以实现以下操作:

API.News.Article.GET(42334);

同时我也不希望能够执行以下操作:

AbstractArticle.GET(42334);

我尝试将每个子类变成类实例字段

public class API {
    // this one is static on purpose to avoid having to instantiate
    // the API class before accessing its fields
    public static final AbstractNews News = new AbstractNews();
}

public class AbstractNews {
    public final AbstractArticle Article = new AbstractArticle();
}

public class Article {
    public void GET(String articleId) {
        // ...
    }
}

这对于我之前想要实现的两点来说效果很好,但是我无法找到一种方法来迭代类字段,从而使我能够正确调用 final方法。

对于之前的逻辑,我需要迭代的全部内容如下:

private static Class classHasSubClass(Class<?> currentClass, String fieldName) {

    Class[] classes;

    classes = currentClass.getClasses();

    for (final Class classItem : classes) {
        if (classItem.getSimpleName().toLowerCase().equals(fieldName)) {
            return classItem;
        }
    }

    return null;

}

但是对于字段的第二次逻辑尝试,我无法正确调用 final方法,可能是因为生成的逻辑实际上试图执行以下操作:

AbstractArticle.GET(42334);

而不是

API.News.Article.GET(42334);

我怀疑这是因为 invoke 方法的第一个参数不能再像我之前那样为 null 并且必须是 的正确等效项API.News.Article.GET(42334);

有没有办法让这项工作有效,或者有更好/不同的方法吗?

最佳答案

我发现实例字段的路径正确,但缺少最后正确调用方法所需的部分信息。

在迭代字段时,我仅使用每个字段的类,之前使用静态类引用工作得很好,因为它们不是实例,但现在它需要字段的实例才能正常工作。

最后,使用迭代方法代替 classHasSubClass 使其正常工作,如下所示:

private static Object getFieldClass(Class<?> currentClass, Object currentObject, final String fieldName) {

    Field[] fieldList;

    fieldList = currentClass.getDeclaredFields();

    for (final Field field : fieldList) {
        if (field.getName().toLowerCase().equals(fieldName)) {

            try {
                return field.get(currentObject);
            } catch (IllegalAccessException e) {

                e.printStackTrace();
                break;

            }

        }
    }

    return null;

}

这样,我始终保留对要调用的最终字段的实例对象引用作为第一个参数传递 (someMethod.invoke(objectInstance);),而不是 null.

关于java - 通过反射不断迭代字段的字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53693988/

相关文章:

通过 webview 显示的 Android 本地镜像模糊

java - 如何在 Android 中动态更改 ListView 的列表项?

java - 当 get 和 is 都存在时,JSTL EL 访问器翻译优先级?

java - 复制文件 Google Drive SDK 时出错

android - 多个 Android Wear 可以与单个 Android 设备配对吗

java - 正则表达式如何获取/之后的所有内容

go - 通用函数来获取 Go 中任何结构的大小

c# - 如何使用 DisplayName 检索属性名称?

java - 从 Java 执行外部程序

java - 如何调试Java编译器源代码(Javac)本身?