【问题标题】:java: Is it possible to know which constructor an enumeration item uses to be initialized?java:是否可以知道枚举项使用哪个构造函数进行初始化?
【发布时间】:2015-09-28 02:53:56
【问题描述】:

正如标题所说,我想知道是否可以通过编程方式了解枚举项用于初始化的构造函数,我认为如果有这样的机制,它应该可以通过使用反射来访问,但我有更具体地说,找不到类似的东西:

我有什么

enum AnEnum {

    E1(1),
    E1(1, 2);

    int v;

    AnEnum(int p1) {
        v = p1;
    }

    AnEnum(int p1, int p2) {
        v = p1 + p2;
    }

} 

我需要的是一种机制,可以告诉我实例是使用一个参数还是两个参数构造函数初始化的,如果我可以获得用于初始化它的参数,那就更好了。

【问题讨论】:

  • “我需要一个机制来告诉我” 你想怎么被告知?为什么不在你的两个构造函数中使用 print 语句来获取所有信息?
  • 问题是我正在编写一个允许我在代码中“自省”的实用程序,比如反编译它,因此在所有情况下我都无法随意访问或修改源代码.所以我可以更好地重新创建代码。
  • 对象没有“历史”来告诉你它们是如何组成的——除非你把它添加到类的代码中。 - 这是一个奇怪的要求。你会从这些信息中得到什么?无论过去如何,对象都是您检查时的样子。
  • @laune 正如我在之前的评论中所说,如果我要重新创建代码,最好的办法是确定它是如何编写的。尽管如此,我知道在我的示例中这并不重要,因为我可以将代码重新创建为:E1(1),E2(3)

标签: java reflection constructor enums initialization


【解决方案1】:

asm 等字节码工具可让您查看某个枚举值是如何构造的。

尝试 java -classpath "asm.jar;asm-util.jar;yourjar.jar" AnEnum 并查看 clinit 方法:

...
mv.visitMethodInsn(INVOKESPECIAL, "temp/AnEnum", "<init>", "(Ljava/lang/String;II)V", false);
mv.visitFieldInsn(PUTSTATIC, "temp/AnEnum", "E1", "Ltemp/AnEnum;");
...
mv.visitMethodInsn(INVOKESPECIAL, "temp/AnEnum", "<init>", "(Ljava/lang/String;III)V", false);
mv.visitFieldInsn(PUTSTATIC, "temp/AnEnum", "E2", "Ltemp/AnEnum;");

你可以看到 E1 是用签名 (String, int, int) 调用的,而 E2 是用签名 (String, int, int, int) 调用的。前导 (String, int) 可能是字符串名称和 Enum 值的数值,因此您应该只对剩余的参数感兴趣。

【讨论】:

  • 这就是我所说的,有没有例子?
  • 你的问题很特殊。此外 - 从类初始化器中提取所需信息使您熟悉 java 字节码、数据流分析和工具 asm。
【解决方案2】:

您将无法检测到调用了哪个构造函数,但构造函数可以简单地存储您可以访问的参数值。在此示例中,我使用整数的 Object 类型。如果使用了第二个构造函数并且没有 p2,则它的值为 null。

enum AnEnum {

    E1(1),
    E2(1, 2);

    int v;
    Integer p1;
    Integer p2;

    AnEnum(int p1) {
        this.v = p1;
        this.p1 = p1;
    }

    AnEnum(int p1, int p2) {
        this.v = p1 + p2;
        this.p1 = p1;
        this.p2 = p2;
    }

    public Integer getP1() {
        return this.p1;
    }

    public Integer getP2() {
        return this.p2;
    }
}

【讨论】:

  • 这是清洁后的官方解决方案,但我认为问题有所不同。
  • 啊,是的,我明白了。我的解决方案通常适用于类。现在,虽然您可以反映枚举的字段以获取实例,但您仍然无法在不拆卸类的静态初始化程序的情况下确定使用了哪个构造函数。
  • 是的,我同意这一点(这就是我写它的原因:)。我的意思是,如果无法修改枚举的代码,则需要反汇编代码。
猜你喜欢
  • 2021-08-03
  • 2012-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多