【问题标题】:Getting a enum constant declared in imported class, via reflection通过反射获取在导入的类中声明的枚举常量
【发布时间】:2013-06-09 23:44:02
【问题描述】:

有类似的东西:

import com.example.test.classA;
import com.example.test.classB;
import com.example.test.classC;

public class MyClass {
    ...
    Flavors p = Flavors.VANILLA;
    ...
    String flavorChoice = "Flavors.CHOCOLATE";
    ...
}

其中Flavors 是在其中一个导入的类中声明的enum

public enum Flavors { CHOCOLATE, VANILLA, LEMON };

如何使用反射从字符串 flavorChoice 中获取值?
不要假设我知道在哪个导入的类 Flavors 中声明。
甚至不要假设Flavors 可以从MyClass 中访问。

澄清
字符串flavorChoices 应该产生Object,在上面的示例中,对象可能是Flavors 类型。但它也可能引用其他枚举中的其他常量:

String flavorChoice = "ExtraFlavors.MENTA";
String flavorChoice = "ExoticFlavors.CHALK";
String flavorChoice = "AnyEmun.ANYCONSTANT";

直到运行时我才知道字符串内容是什么。我希望能够:

  1. 检查引用的枚举确实存在并且可以从 MyClass 访问
  2. 获取引用的枚举常量并将其放入Object

【问题讨论】:

  • 如果您不知道要引用哪个特定的 Flavors 类,那么这怎么可能起作用?
  • 也许this question,经过一些修改,可能有用吗?
  • 实际上,您为什么不知道 Flavors 类的声明位置?即使你通过反射得到它,如果你没有导入它,你也只能将它存储为Object(或Enum<?>)......
  • @OliCharlesworth 这就是为什么我在示例中放置Flavors p = Flavors.VANILLA 行,以表明无需反射我可以使用Flavors,而无需确切知道它的声明位置。为简单起见,如果它有助于您制定答案,假设系统中只声明了一个Flavors
  • @WChargin 实际上,我知道Flavors 的声明位置。我事先不知道的是字符串flavorChoice,它可以引用任何在该范围内可见的enum。它甚至可以引用一些在那里无法访问的enum,在这种情况下我想调用RuntimeException

标签: java reflection


【解决方案1】:

如果字符串被重新定义如下:

String flavorChoice = "CHOCOLATE";

你甚至不需要反思。只需使用Flavors.valueOf(flavorChoice)

在你的情况下,你可以说:

String choice = "Flavors.CHOCOLATE";
String[] fragments = choice.split("\\."); 
Enum.valueOf(Class.forName(fragments[0]), fragments[1]);

Class.forName(fragments[0]) 将返回您的enum 的类,Enum.valueOf() 返回enum 的元素。

编辑: 如果在实际情况下您的类属于包,您应该通过将 split() 替换为其他内容来改进解析。

【讨论】:

  • 只要我需要为Class.forName() 提供课程,这对我没有帮助。我需要一种方法来检查Flavors 是否是范围内的已知类(请注意,“范围内的已知类” 比检查当前对象子类要广泛得多,它可能是一个类因为import 或者因为层次结构中的某个父类声明了它而知道)
  • @ilomambo:AFAIK,没有关于反射机制可用的词法范围的信息。因此,您所要求的可能是不可能的。
【解决方案2】:

如果您有权访问Flavors 类,如示例所建议的,valueOf 方法可能有用:

返回具有指定名称的此类型的枚举常量。该字符串必须与用于在此类型中声明枚举常量的标识符完全匹配。 (不允许使用无关的空白字符。)

因此:

Flavor f = Flavors.valueOf("VANILLA");

如果您的问题是如何从Flavors.VANILLA 中提取VANILLA,您可以尝试:

Flavor f = Flavors.valueOf("Flavors.VANILLA".replaceAll("^.*\\.", ""));

其中* 是一个贪心量词。

使用正则表达式而不是split("\\.")[1] 的优势在于,如果参数具有更大的限定条件,例如classA.Flavors.VANILLAcom.example.test.classA.Flavors.VANILLA,则正则表达式仍然可以工作。或者,您可以使用:

String[] parts = "Flavors.VANILLA".split("\\.");
String flavorPart = parts[parts.length - 1];

【讨论】:

  • 更好的正则表达式 - 它也适用于 SomeClass.Flavors.VANILLA
  • 你也应该在拆分中使用它
  • @assylias 我添加了split 部分以表明即使是最简单的正则表达式也可以做到这一点,因为有些人不喜欢使用复杂的正则表达式。如果是这种情况,我实际上认为这样做会更好java.util.regex.Pattern.quote(".").split(identifierString) 但也许这只是我......
  • @WChargin 除了我在原始问题中对您的回复评论。如果我可以使用Flavors,那很好,但请注意我写了“甚至不要假设可以从MyClass 中访问Flavor”。也许这个问题过于简单了,我会在那里添加一些澄清。
  • 如果你能做到Flavors p = Flavors.VANILLA那么你可以打电话给Flavors.valueOf;我错过了什么吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 2014-06-30
  • 1970-01-01
相关资源
最近更新 更多