Java为java.lang.Number或原始类型的通用子类获取valueOf [英] Java get valueOf for generic subclass of java.lang.Number or primitive

查看:124
本文介绍了Java为java.lang.Number或原始类型的通用子类获取valueOf的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读了许多问题之后,我问自己是否有可能解决不使用硬编码方法将字符串转换为通用数字的难题。

After reading through a lot of questions, I asked myself if it is possible to solve the dilemma of transforming a string into a generic number WITHOUT using a hardcoded approach.

例如:我从一个方法中获取类型为Class
的参数Number.isAssignableFrom,或者我可以通过其他方式检查的参数(如果这是数字类)。但是我也从用户那里得到输入。作为字符串。

For example: I get from a method a parameter with the type Class With Number.isAssignableFrom or other ways I can check, if this is a number class. But I also get from the user an input. As a string.

问题是:我现在可以以某种方式将此字符串转换为所请求的数字对象,而无需为每种情况构建一个if语句吗?

The question is: Can I now somehow transform this string into the requested number object without building an if statement for every case?

示例代码,无法正常工作:

Example code, properly not working:

Object ret = null;

for(int i=0;i<method.getParameterTypes().length; i++ ) {
    Class<?> param = method.getParameterTypes()[i];
    String argString = getUserInput(_in, "Argument ("+param.getSimpleName()+"): ");

    if( Number.isAssignableFrom(param) )
        ret = ((Class<NumberChild>)param).valueOf(argString);
    /// OR
        ret = param.cast( Double.valueOf(argString) )
}

这个问题甚至更进一步:是否可以通过上述方式以类似的方式转换每个基元?

The even advance this question: Could it be possible to cast every primitive in something similar in from the above way?

注意:这里的方法应该完全专注于非硬编码的解决方案。我当前正在运行的代码使用对每种情况进行硬编码的方法。但是在那种情况下,更通用的解决方案会更有趣。

Note: The approach here should completely focus on a non hardcoded solution. My currently running code uses the approach of hardcoding every single case. But in those cases a more general solution would be much more interesting.

编辑:
很抱歉,我的误解是,我的意思是用一种硬编码的方法,这种方法可以测试所有可能的情况,例如:

I'm sorry for misunderstandings, but I mean with an hardcoded approach, an approach that tests through every possible case like:

 if( integer ); do ...
 if( double ); do ...
 if( long ); do ...

但这就是我想解决的问题。澄清一下:这只是一个挑战。我的生活或代码并不取决于它,我只是想知道是否有可能!

But that is exactly, what I want to work around. To clarify: This is just a challenge. My life or code is not depending on it, I just want to know IF it is possible!!

推荐答案

更新

由于原始答案(请参见下文)中描述的方法不支持基元,因此只能支持具有单个 String 参数,最好为每个类明确指定要使用的解析器方法。

Since the method described in the original answer (see below) doesn't support primitives, and can only support classes which has a constructor with a single String parameter, it would be better to explicitly specify the parser method to use, for each class.

使用Java 8

如您所见,即使是原始值也可以使用适当的parse方法进行处理,但是 parse( )方法仍然返回 Object ,因此仍将任何原始值装箱。通过反射处理基元时通常是这种情况。

As you can see, even primitive values can be handled, with appropriate parse method, however the parse() method here still returns Object, so any primitive value is still boxed. That is usually the case when handling primitives through reflection.

这是一个简化的示例。有关完整的工作示例,请参见 IDEONE

This is a reduced example. See IDEONE for full working example.

private static HashMap<Class<?>, Function<String,?>> parser = new HashMap<>();
static {
    parser.put(boolean.class   , Boolean::parseBoolean); // Support boolean literals too
    parser.put(int.class       , Integer::parseInt);
    parser.put(long.class      , Long::parseLong);
    parser.put(Boolean.class   , Boolean::valueOf);
    parser.put(Integer.class   , Integer::valueOf);
    parser.put(Long.class      , Long::valueOf);
    parser.put(Double.class    , Double::valueOf);
    parser.put(Float.class     , Float::valueOf);
    parser.put(String.class    , String::valueOf);  // Handle String without special test
    parser.put(BigDecimal.class, BigDecimal::new);
    parser.put(BigInteger.class, BigInteger::new);
    parser.put(LocalDate.class , LocalDate::parse); // Java 8 time API
}

@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object parse(String argString, Class param) {
    Function<String,?> func = parser.get(param);
    if (func != null)
        return func.apply(argString);
    if (param.isEnum()) // Special handling for enums
        return Enum.valueOf(param, argString);
    throw new UnsupportedOperationException("Cannot parse string to " + param.getName());
}






原始答案

用于 Number (Java 7)列出了以下直接已知子类,并显示了用于解析单个<$ c的方法$ c> String 参数:

  • Byte, new Byte(String s), valueOf(String s), decode(String nm)
  • Short, new Short(String s), valueOf(String s), decode(String nm)
  • Integer, new Integer(String s), valueOf(String s), decode(String nm)
  • Long, new Long(String s), valueOf(String s), decode(String nm)
  • Double, new Double(String s), valueOf(String s)
  • Float, new Float(String s), valueOf(String s)
  • BigDecimal, new BigDecimal(String val)
  • BigInteger, new BigInteger(String val)
  • AtomicInteger
  • AtomicLong

如您所见,最好使用带有 String 参数的构造函数。这样, BigDecimal BigInteger 也将得到支持。

As you can see, you'd be best off using a constructor with a String parameter. That way would will get support for BigDecimal and BigInteger too.

现在,关于如何。使用反射。您有 Class ,因此要求它作为构造函数,然后调用它。

Now, as for how. Use reflection. You have the Class, so ask it for the constructor, and invoke it.

Class param = /*code here*/;
String argString = /*code here*/;

Object ret;
try {
    Constructor ctor = param.getConstructor(String.class);
    ret = ctor.newInstance(argString);
} catch (ReflectiveOperationException e) {
    throw new UnsupportedOperationException("Cannot convert string to " + param.getName());
}

这篇关于Java为java.lang.Number或原始类型的通用子类获取valueOf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆