如何在Java中检查一个字符串是否是给定的Class<?>类型

20

好的,这是一个有点复杂的问题,我完全迷失了。

假设你有一个字符串和一个通用类。像这样。

String string;
Class<?> clazz;

你如何检查字符串是否表示了一个可以与该类相等的值。

例如,假设:

String string = "true";
Class<?> clazz = Boolean.class;

我该如何检查字符串"true"是否为布尔类型?

这里有另一个例子。假设:

String string = "true";
Class<?> clazz = Integer.class;

我该如何检查并确认字符串 "true" 不是一个整数?


你想只对Wrapper类型进行测试吗? - Rohit Jain
我主要关注原始类型包装器,是的。 - Zach Sugano
6个回答

21

考虑到你只想对包装类型实现此功能,可以在这里使用一些反射技巧(为简洁起见,忽略了与无关代码的异常处理):

String string = "ABC";
Class<?> clazz = Integer.class;

Method method = clazz.getDeclaredMethod("valueOf", String.class);

if (method != null) {
    try {
        Object obj = method.invoke(null, string);       
        System.out.println("Success : " + obj);

    } catch (InvocationTargetException ex) {
        System.out.println("Failure : " + string + " is not of type " + 
                                          clazz.getName());
    }
}

考虑到每个包装类都有一个 静态 valueOf 方法,它接受一个 String 类型的参数,并返回该 wrapper 类型的值。如果参数无法转换为相应的包装类型,则会抛出异常。
因此,在上述情况下,如果抛出异常,则说明 string 值不是 clazz 类型。
附注:对于 Boolean.class,任何非 "true" 的字符串都将被视为false

1
我假设您正在实现某种规范/协议或类似内容。
  1. 查看规范。
  2. 定义有效输入的语法。
  3. 解析该语法。
这类似于编程语言对字面量的处理。

0

在JavaScript中,您可以使用eval()函数来处理字符串。但在Java中,您没有这样的方法。您需要为此检查实现自己的启发式算法。

然而,您可以尝试使用给定类解析字符串。例如:

Iteger.parseInt(stringValue);

如果解析成功,那么该字符串可以用作该类型的值。如果失败,则会抛出异常。实现这些检查,然后得出一些结论。

我不能仅仅使用那个方法,因为我不知道这个类是否是整数。它是一种通用类型。 - Zach Sugano
你的问题没有单行解决方案。这就是为什么我说你需要实现一系列的检查,然后得出结论。 - allprog
我并不期望得到一行代码的解决方案。我只是认为,肯定有比检查它是否为任何原始类型或我添加的其他类,然后将其与我添加的每个类进行比较更好的方法。 - Zach Sugano
你接受了基本上建立在我提出的相同想法上的答案。只是使用了反射并且基于原始类型具有valueOf方法这一事实。很好,我确认了。然而,请尽量不要重复造轮子,使用JSON或ProtocolBuffers来定义消息。它们比编写自己的启发式解析器更少出错且跨平台。 - allprog

0

我现在无法测试这个解决方案,但为什么不尝试这样做呢?如果你能自己列举出所有可能的类,只需在类上创建一些switch语句即可。

boolean isStringClass (Class clazz, String string) {

    try {
        if (Integer.class == clazz) {
           Integer.valueOf(string);
        } else if (Boolean.class = clazz) {
           Boolean.valueOf(string);
        } [...etc]
    } catch (Exception e) {
        return false;
    }

    return true;
}

当然,您需要了解所有可能的类,并且您需要知道属于该类的一种方法,该方法能够解析字符串并返回其类型。对于原始包装器,这将是valueOf

如果您计划仅转换包装器,则Rohit的解决方案将是更好的选择。但是,如果您不这样做,并且无法向此新类添加valueOf方法,则这可能是您唯一的选择。


0

我会考虑使用JavaBeans的PropertyEditor机制来完成此操作。

@Test
public void testIsOfType() {        
    assertFalse(test("nope", Integer.class));
    assertFalse(test("nope", Boolean.class));

    assertTrue(test("1", Integer.class));
    assertTrue(test("true", Boolean.class));
}

boolean test(String str, Class<?> clazz) {
    PropertyEditor propertyEditor = PropertyEditorManager.findEditor(clazz);
    if (propertyEditor != null) {
        try {           
            propertyEditor.setAsText(str);
            return true;
        } catch (Exception ex) {}
    }
    return false;
}

这样可以避免显式反射的需要,如果您决定需要测试除原始包装器之外的类,您可以使用PropertyEditorManager.registerEditor()注册新的编辑器。

不幸的是,这仍然存在Rohit解决方案中的问题,即test("1", Number.class)将失败。


0

虽然这个问题已经过去了很长时间,但我想在@Rohit的答案中补充一点,假设使用的类没有valueOf方法。可以尝试以下方法:

Class<?> aClass = Class.forName("full-class-name");
try {
    Method method = aClass.getDeclaredMethod("valueOf", String.class);
    method.invoke(null, value);
} catch (NoSuchMethodException e) {
    aClass.getConstructor(aClass).newInstance("value");
}

在第二种情况下,该类必须有一个接受字符串的构造函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接