Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从字符串转换为基本类型或标准java包装类型_Java_String_Object_Reflection_Type Conversion - Fatal编程技术网

如何从字符串转换为基本类型或标准java包装类型

如何从字符串转换为基本类型或标准java包装类型,java,string,object,reflection,type-conversion,Java,String,Object,Reflection,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)

我有一个
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?
}
上述情况甚至不是我迄今为止看到的最糟糕的:)


有人在这里有秘密把戏吗?

据我所知,除了你介绍的版本,没有真正的替代品。您可以稍微简化它(因为包装器类型都是
final
),但您基本上需要使用
if
switch
或哈希来打开类

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


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;
}
这更简单、更有效。它与原始版本相当,因为类都是
final
,并且规范规定
Class
对象的相等性是对象标识

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

我不认为这不那么难看。。。但是“美”并不是衡量代码质量的有用标准,因为它是主观的,并且不能告诉您代码是否易于理解和/或维护

更新

为了支持原语类型,将相应的类添加到
if
条件中;e、 g

    if (Boolean.class == clazz || Boolean.TYPE == clazz) {
        return Boolean.parseBoolean(value);
    }
现在,在类型名称上进行字符串切换可能会更有效,尽管在类型标识方面有一些稍微棘手的问题需要仔细考虑。(理论上,您可以有多个全名相同的类型,这些类型已经由不同的类加载器加载。我认为您需要在类加载器中“快速而松散”地使用原始包装类实现这一点……但我认为这仍然是可能的。)

我建议:

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
    }
}
List>();
clsList.add(Boolean.class);
clsList.add(Integer.class);
//等等。
用于(类别cls:clsList){
if(cls.isAssignableFrom(clazz)){
返回cls.getMethod(“valueOf”,新类[]{String.Class}).invoke(null,新对象[]{value});
//本例中缺少:处理一些异常
}
}

这看起来干净还是难看,我就留给你了。

我想我找到了什么

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();
}
导入java.beans.PropertyEditor;
导入java.beans.PropertyEditorManager;
@凌驾
公共对象调用(对象代理、方法、对象[]args)抛出Throwable{
字符串返回值=。。。
返回转换(方法.getReturnType(),returnValue);
}
私有对象转换(类targetType,字符串文本){
PropertyEditor编辑器=PropertyEditorManager.findEditor(targetType);
编辑器.setAsText(文本);
返回editor.getValue();
}
我认为这3行代码比多个ifs更好,我避免了添加外部库依赖项,因为
java.beans
包位于java标准库(javadocs:)中

我觉得这是可以接受的;我唯一的困惑是
propertyEdit
包含在
java.beans
包中,我更喜欢
java.util
java.lang.reflect
包中提供的东西,因为该代码实际上与
java.beans
无关

上面的代码还有一个优点,您可以注册额外的
propertyEdit
实例来翻译复杂的对象,顺便说一句,这不是一件坏事


我认为它比一个ifs列表更好,不仅美观,而且质量也更好。

有一个轻量级的库,它可以将字符串解析为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());
}

在jdk8中,您现在可以在没有if语句的情况下执行类似于so(1)的查找时间

现在有一个更好的版本可以正确处理空值

也许能帮上忙

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

告诉我们:1。为什么第一个示例不起作用,以及2。“似乎不合适”是什么意思。第一个示例不起作用,因为在convert方法中它缺少实现(这是本问题的主题)2。这似乎不合适,这意味着在我看来,由于有很多ifs,这个实现相当丑陋,我认为有更好的方法来完成这项工作。因为第二个例子有效(但它只是丑陋),可能是一个更好的选择。谢谢@luiscubal,这是真的,它有效,但我不希望我的代码库中有丑陋的东西;我无法观看:)我希望本机方法isAssignableFrom()作为第一个操作执行==检查,因此您提出的改进不会产生太大的影响。谢谢你的提示。我宁愿故意让丑陋的代码看起来更糟糕,作为以后替换它的纪念(再次开玩笑)。我可以考虑的另一个避免反射的选项是创建一个映射。这不适用于基本类型:int.class.getMethod(“valueOf”,新类[]{String.class})投掷NoSuchMethodException@LuigiR.Viggiano-应该指出的是,您尝试替换的代码也不能与原语一起使用。这是一个很好的方法。但是为什么要迭代硬编码类型呢??这正是它所解决的问题。为什么不返回returnType.getMethod(“valueOf”,String.class).invoke(null,stringValue)它实际上适用于您枚举的所有基本类型。不适用于原子*.class类,以及一些异常(如果通过反射更改构造函数(字符串)的值,则支持某些异常),li
private Map<Class<?>, Function<String, Object>> classToUnmarshaller = new HashMap<>();
private Map<Class<?>, Function<Object, String>> classToMarshaller = new HashMap<>();

public ObjectTranslator() {
    classToUnmarshaller.put(Boolean.class, s -> s == null ? null : Boolean.parseBoolean(s));
    classToUnmarshaller.put(Boolean.TYPE, s -> Boolean.parseBoolean(s));
    classToUnmarshaller.put(Byte.class, s -> s == null ? null : Byte.parseByte(s));
    classToUnmarshaller.put(Byte.TYPE, s -> Byte.parseByte(s));
    classToUnmarshaller.put(Short.class, s -> s == null ? null : Short.parseShort(s));
    classToUnmarshaller.put(Short.TYPE, s -> Short.parseShort(s));
    classToUnmarshaller.put(Integer.class, s -> s == null ? null : Integer.parseInt(s));
    classToUnmarshaller.put(Integer.TYPE, s -> Integer.parseInt(s));
    classToUnmarshaller.put(Long.class, s -> s == null ? null : Long.parseLong(s));
    classToUnmarshaller.put(Long.TYPE, s -> Long.parseLong(s));
    classToUnmarshaller.put(Float.class, s -> s == null ? null : Float.parseFloat(s));
    classToUnmarshaller.put(Float.TYPE, s -> Float.parseFloat(s));
    classToUnmarshaller.put(Double.class, s -> s == null ? null : Double.parseDouble(s));
    classToUnmarshaller.put(Double.TYPE, s -> Double.parseDouble(s));
    classToUnmarshaller.put(String.class, s -> s);

    classToMarshaller.put(Boolean.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Boolean.TYPE, s -> s.toString());
    classToMarshaller.put(Byte.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Byte.TYPE, s -> s.toString());
    classToMarshaller.put(Short.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Short.TYPE, s -> s.toString());
    classToMarshaller.put(Integer.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Integer.TYPE, s -> s.toString());
    classToMarshaller.put(Long.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Long.TYPE, s -> s.toString());
    classToMarshaller.put(Float.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Float.TYPE, s -> s.toString());
    classToMarshaller.put(Double.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Double.TYPE, s -> s.toString());
    classToMarshaller.put(String.class, s -> s == null ? null : s.toString());
}

public Function<String, Object> getUnmarshaller(Class<?> paramTypeToCreate) {
    return classToUnmarshaller.get(paramTypeToCreate);
}

public Function<Object, String> getMarshaller(Class<?> type) {
    return classToMarshaller.get(type);
}
primitiveTranslator.getConverter(Integer.TYPE).apply(stringToConvert);
import org.apache.commons.beanutils.ConvertUtils;
// ...
final Object v = ConvertUtils.convert("42", Integer.class);