如何将String转换为基本类型或标准java Wrapper类型

Lui*_*ano 21 java string reflection object type-conversion

我有一个java.lang.reflect.InvocationHandler,我需要实现方法invoke()

我有java.lang.String详细的类型值,我需要将此值转换为方法所期望的相应returnType(它可以是像int,boolean,double或包装类一样的原语,如Boolean,Integer,Double,Float等) .

例:

public Object invoke(Object proxy, Method method, Object[] args) 
        throws Throwable {
    String computedValue = compute(...);
    return convert(method.getReturnType(), computedValue);
}

private Object convert(Class<?> returnType, String stringValue) {
    return ...; // what's the simplest way?
}
Run Code Online (Sandbox Code Playgroud)

我不希望简单地在复杂对象之间实现自动转换,但我期望从String转换为标准java类型的简单方法.

我曾经多次看过这样的东西,但这对我来说似乎不合适:

public static Object toObject( Class clazz, String value ) {
    if( Boolean.class.isAssignableFrom( clazz ) ) return Boolean.parseBoolean( value );
    if( Byte.class.isAssignableFrom( clazz ) ) return Byte.parseByte( value );
    if( Short.class.isAssignableFrom( clazz ) ) return Short.parseShort( value );
    if( Integer.class.isAssignableFrom( clazz ) ) return Integer.parseInteger( value );
    if( Long.class.isAssignableFrom( clazz ) ) return Long.parseLong( value );
    if( Float.class.isAssignableFrom( clazz ) ) return Float.parseFloat( value );
    if( Double.class.isAssignableFrom( clazz ) ) return Double.parseDouble( value );
    return value;
}
Run Code Online (Sandbox Code Playgroud)

以上甚至不是我看到的更糟糕的,到目前为止:)

有人在这里有秘密技巧吗?

Ste*_*n C 26

据我所知,你提供的版本没有真正的替代品.你可以把它简化一点(因为包装类型都是final),但你实际上需要使用ifswitch或散列对班级进行切换.

我的建议是像上面那样对它进行编码.丑陋的代码本身只是一个问题,如果你不得不看它.所以把它放在一个实用工具方法中,不要再看它了.


FWIW - 这就是我简化方法的方法:

public static Object toObject( Class clazz, String value ) {
    if( Boolean.class == clazz ) return Boolean.parseBoolean( value );
    if( Byte.class == clazz ) return Byte.parseByte( value );
    if( Short.class == clazz ) return Short.parseShort( value );
    if( Integer.class == clazz ) return Integer.parseInt( value );
    if( Long.class == clazz ) return Long.parseLong( value );
    if( Float.class == clazz ) return Float.parseFloat( value );
    if( Double.class == clazz ) return Double.parseDouble( value );
    return value;
}
Run Code Online (Sandbox Code Playgroud)

这更简单,更有效.它等同于原始版本,因为类是全部的final,因为规范声明Class对象的相等性是对象标识.

可以说,我们应该使用<wrapper>.valueOf(String)直接返回包装器对象的方法.

我没有声称这不那么丑陋...但"美"并不是衡量代码质量的有用方法,因为它是主观的,因为它不会告诉你代码是否易于理解和/或维护.

UPDATE

要同样支持基本类型,请将相应的类添加到if条件中; 例如

    if (Boolean.class == clazz || Boolean.TYPE == clazz) {
        return Boolean.parseBoolean(value);
    }
Run Code Online (Sandbox Code Playgroud)

它现在可能已经到了这样的程度,即对类型名称进行字符串切换更有效,尽管有一些类型标识的问题需要仔细考虑.(理论上,您可以使用由不同类加载器加载的具有相同全名的多个类型.我认为您需要在类加载器中"快速且松散地"使用原始包装类来执行此操作...但是我认为它仍有可能.)

  • +1 - 同意,这也是我能想到的那么简单.就个人而言,我宁愿花费所有"额外"工作来使用泛型和地图来从转换中获取实际类型,而不是对象引用(以后可能需要进一步转换才能使用!). (3认同)

Lui*_*ano 21

我想我找到了些东西

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String returnValue = ...
    return convert(method.getReturnType(), returnValue); 
}

private Object convert(Class<?> targetType, String text) {
    PropertyEditor editor = PropertyEditorManager.findEditor(targetType);
    editor.setAsText(text);
    return editor.getValue();
}
Run Code Online (Sandbox Code Playgroud)

我认为这三行代码比多个ifs更好,并且我避免添加外部库依赖项,因为java.beanspackage在Java标准库(javadocs :)中PropertyEditorManager.

我发现它完全可以接受; 我唯一的困惑是PropertyEditor包含在java.beans包中,我会更喜欢可用的东西java.utiljava.lang.reflect包,因为这段代码与java.beans实际上没有任何关系.

上面的代码还有一个优点,你可以注册其他PropertyEditor实例来翻译复杂的对象,顺便说一句.尽管如此,这并不是一件坏事.

我认为它比ifs,美容,质量更好.


Bor*_*orv 7

可能org.apache.commons.beanutils.ConvertUtils可以帮忙吗?

import org.apache.commons.beanutils.ConvertUtils;
// ...
final Object v = ConvertUtils.convert("42", Integer.class);
Run Code Online (Sandbox Code Playgroud)


lui*_*bal 5

我提出这个:

List<Class<?>> clsList = new ArrayList<Class<?>>();
clsList.add(Boolean.class);
clsList.add(Integer.class);
//etc.

for (Class<?> cls : clsList) {
    if (cls.isAssignableFrom(clazz)) {
        return cls.getMethod("valueOf", new Class[] { String.class }).invoke(null, new Object[] { value });
        //Missing in this example: Handle a few exceptions
    }
}
Run Code Online (Sandbox Code Playgroud)

无论这看起来更干净还是更丑,我都会留给你。


etx*_*lpo 5

有一个轻量级库可以将字符串解析为 Java 类型,它可以满足您的需求。这就是所谓的类型解析器和你可以找到它在Github这里

你上面的代码可能看起来像这样:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    TypeParser parser = TypeParser.newBuilder().build();
    String computedValue = compute(...);
    return parser.parseType(computedValue,  method.getGenericReturnType());
}
Run Code Online (Sandbox Code Playgroud)