6

我想构建一个可以Field通过 Java 反射将字符串值转换为给定对象数据类型的方法。

这是我的代码:

String value = ...;

Class<? extends MyObject> clazz = getClazz();

Field f = clazz.getDeclaredField("fieldName");
boolean fieldIsAccessible = f.isAccessible();
if (!fieldIsAccessible) {
   f.setAccessible(true);
}

f.getType().cast(value);

if (!fieldIsAccessible) {
    f.setAccessible(false);
}

当我第一次尝试运行此代码时,我收到此异常java.lang.ClassCastException

我想转换value为 class java.math.BigDecimal

我的代码缺少什么?

编辑: 查看我想出的解决方案。

4

10 回答 10

11

您可以为具有这样的字符串构造函数的类进行此操作: f.getType().getConstructor( String.class ).newInstance( value );

于 2012-11-26T16:52:19.367 回答
3

在 Java 中,没有将 String 转换为任意类的实例的通用方法。许多类根本不支持这种转换。对于那些支持它的人来说,没有标准的接口。

您最好的选择是寻找一个接受 String 作为其唯一参数的构造函数。当然,并非每个类都提供这样的构造函数,并且无法保证语义会如您所愿。

于 2012-11-26T16:44:13.580 回答
3

有一个名为 type-parser 的 Github 项目(MIT 许可),它将字符串值转换为所需的数据类型

这是来自GitHub的项目描述

这是一个轻量级库,除了将字符串解析为给定类型之外什么都不做。支持所有适用的 java 类,如 Integer、File、Enum、Float 等,包括通用 Collection 类型/接口,如 List、Set、Map、数组甚至自定义类型。也可以注册自己的解析器。

于 2015-04-15T13:47:11.273 回答
1

正如 maerics 所说,您不能只将 String 转换为数据类型。您的意思是“我如何从字符串中解析 BigDecimal”,答案是……

fieldName = new BigDecimal(value);
于 2012-11-26T16:45:34.310 回答
1

如果对象不为 null 并且不能分配给类型 T,则 Class cast 方法将引发 ClassCastException。只有少数几种类型的变量可以分配 String 引用,即 String、Object、Serializable、Comparable 和 CharSequence。

许多(但不是全部)类都有基于字符串生成对象实例的方法。在某些情况下,包括 BigDecimal,有一个构造函数采用字符串表示新对象的值。您可以使用指定单个 String 参数的 Class getDeclaredConstructor 方法来获取此类构造函数的 Constructor 对象(如果有的话)。但是,如果不调用某些 setXXX 方法,您将无法获得有用的对象,并且这种方法仅限于那些具有正确构造函数形式的类。

您可能正在尝试解决一些更高级别的问题,可能与序列化和反序列化有关。这个问题可能比您当前的问题更容易解决。

于 2012-11-26T16:58:32.423 回答
1

也许没有回答如何将 String 转换为 java 类型的问题,因为没有通用的方法。但是有一个图书馆可以帮助你解决这个问题。请参阅类型解析器库。上面的代码截图如下所示:

    String value = ...;

    Class<? extends MyObject> clazz = getClazz();

    Field f = clazz.getDeclaredField("fieldName");
    boolean fieldIsAccessible = f.isAccessible();
    if (!fieldIsAccessible) {
       f.setAccessible(true);
    }

    TypeParser parser = TypeParser.newBuilder().build();

    // parse value to whatever type f.getGenericType() returns
    Object o = parser.parseType(value, f.getGenericType());


    if (!fieldIsAccessible) {
        f.setAccessible(false);
    }
}
于 2014-04-14T11:27:22.247 回答
1

我也经历过同样的场景。粘贴我在做了一些研究后编写的代码。小伙伴们觉得有什么不对的地方请指教。

 private <T extends Object> T convertStringToType(String value,Class type){

    if( type.equals(Double.class)){
        return (T) Double.valueOf(value);
    }
    else if(type.equals(Integer.class)){
        if(value.contains(".")){
            BigDecimal bigDecimal= new BigDecimal(value);
            return (T) (Integer)bigDecimal.intValue();
        }
        return (T) Integer.valueOf(value);
    }
    else{ // add other type which you need
        throw new Exception("Invalid type");
    }
}
于 2019-12-26T08:10:06.630 回答
1

您可以使用创建一个小方法Supplier并使用以下方法读取字符串Scanner

    private static <T> T getTokenValue(Supplier<T> supplier) {

       return supplier.get();
    }

    String line = "12.0";

    Scanner scanner = new Scanner(line);
    double value = getTokenValue(scanner::nextDouble);

如果我们需要获取 int,调用会像,

getTokenValue(scanner::nextInt)

该代码是一个示例,可以使用vavr依赖项和 Try 子句进行改进,这些子句可以使用更通用的代码引发自定义异常。

Try.ofSupplier(supplier).getOrElseThrow(new RuntimeException("Custiome message")); 

varv 有很多控制逻辑,可以用来编写更通用的代码。

于 2021-02-22T06:24:00.820 回答
0

这是我想出的解决方案:

public static Object parse(String value, Class<?> clazz) throws NotSupportedException {
    String canonClassName = clazz.getCanonicalName();

    if (canonClassName.equalsIgnoreCase("java.math.BigDecimal")) {
        return new BigDecimal(value);
    }

    // Add other supported classes here ...

    throw new NotSupportedException("The class [" + canonClassName  + "] is not supported.");
}
于 2012-11-30T10:15:42.907 回答
0

我在这个线程中找到了答案:如何将字符串对象转换为布尔对象?- 您可以使用以下方法将字符串解析为布尔值:

Boolean boolean1 = Boolean.valueOf("true");
boolean boolean2 = Boolean.parseBoolean("true");
于 2015-02-02T14:21:41.233 回答