类型转换和泛型

时间:2018-03-29 12:48:14

标签: java generics return-value nested-generics

我正在研究一个消息解析库,其中消息体在每种情况下都以字符串形式返回。我想创建一个能自动将结果转换为正确类型的函数,但我不确定它是否可行。

我的结构是这样的: 我有一个名为ReturnType的枚举。这包含了它包含返回类型的类变量。

我有一个功能映射,它将用户尝试调用的函数映射到消息响应的返回类型。

我认为我有一点工作,但问题是我必须将我想要的类包含在getTypedValue()方法调用中,我认为这是多余的,因为我已经知道基于ReturnType变量的返回类型在功能图中。这是一些代码:

public enum ReturnType {
    NA(String.class),
    INTEGER(Integer.class),
    JSON(JsonElement.class),
    STRING(String.class),
    FLOAT(Float.class),
    DOUBLE(Double.class),
    IP_ADDRESS(InetAddress.class),
    UNKNOWN(String.class),
    BOOLEAN(Boolean.class);

    private Class<?> c;

    <T> ReturnType(Class<T> clazz) {
        this.c = clazz;
    }

    public Class<?> getClazz() {
        return this.c;
    }
}

这是我的getTypedValue()方法:

public <T> T getTypedValue(String functionName, String value, Class<T> clazz) {
        ReturnType type = this.getReturnType(functionName);
        //TODO: Finish this
        if(type.getClazz().equals(clazz)) {
            switch(type) {
                case DOUBLE:
                    break;
                case FLOAT:
                    break;
                case INTEGER:
                    return clazz.cast(Integer.parseInt(value));
                case IP_ADDRESS:
                    break;
                case JSON:
                    break;
                case STRING:
                    return clazz.cast(value);
                case UNKNOWN:
                    return clazz.cast(value);
                default:
                    return clazz.cast(value);
            }
            return null;
        }else {
            throw new UnsupportedOperationException(functionName +" does not support that class("+clazz.getSimpleName()+")");
        }
    }

以下是用户如何调用get typed值。为了简化,我输入了一个静态值(15),但这实际上是一个从消息响应中获取结果的方法调用:

Integer volume = fm.getTypedValue("VOLUME", "15", Integer.class);

有没有办法让它在不提供课程的情况下返回正确的类型?即

Integer volume = fm.getTypedValue("VOLUME", "15");
Double minutes = fm.getTypedValue("MINUTES", "15.25");
Boolean isRunning = fm.getTypedValue("IS_RUNNING","true");

我不确定它是否可能,即使它是,我认为我现在的代码可能有点难看并且难以理解。

3 个答案:

答案 0 :(得分:0)

可悲的是,没有办法。编译器期望在运行时期间类型丢失,这会使将其分配给Object以外的任何其他内容不安全

或者,您可以返回Object并进行多次instanceof检查,但我认为情况更糟。

另一种方法是使用提供的通用调用该方法。不幸的是,我不确定这是否会导致其他编译错误。尝试像

这样的东西
Double minutes = fm.<Double>getTypedValue("MINUTES", "15.25");

向泛型方法提供Class实例没有任何问题,我在许多不同的库中都看到过它。

答案 1 :(得分:0)

你可以实现这一点,但你将失去编译器给你的优势,在编译时检查类型是否正确。

使用类似于{/ p>的getTypedValue实现

@SuppressWarnings({ "unchecked" })
public <T> T getTypedValue(String functionName, String value) {
    ReturnType type = this.getReturnType(functionName);
    switch(type) {
        case DOUBLE:
        case FLOAT:
        case JSON:
        case IP_ADDRESS:
            break;
        case INTEGER:
            return (T) Integer.valueOf(value);
        case STRING:
        case UNKNOWN:
        default:
            return (T) value;
    }
    return null;
}

您可以毫无问题地使用它:

int volume = fm.getTypedValue("VOLUME", "15");

但是,另一方面你也可以使用它(并且编译器不会显示任何错误)

String volume = fm.getTypedValue("VOLUME", "15");

您将收到类型为ClassCastException的运行时异常,例如:

  

java.lang.Integer无法强制转换为java.lang.String

如果你想要某些可能不易出错(在编译时显示错误而不是运行时),你可以定义你在类中处理/知道/提供的所有函数(枚举确实不处理泛型)。

public final class Function<T> {
    private final Class<T> type;
    private Function(Class<T> type) {
        this.type = type;
    }
    public Class<T> getType() {
        return type;
    }
    public static final Function<Integer> VOLUME = new Function<>(Integer.class);
    public static final Function<Boolean> IS_RUNNING = new Function<>(Boolean.class);
    public static final Function<String> NAME = new Function<>(String.class);
}

您可以根据需要进行重构,也可以添加ReturnType。您可以在Function中添加一些自定义逻辑。也可以在构造函数参数中传递函数的名称,如果您需要稍后的名称

然后稍微更改getTypedValue方法:

public <T> T getTypedValue(Function<T> function, String value) {
    ReturnType returnType = ReturnType.getReturnTypeByClass(function.getType());
    // ... same as before
}

您可以创建方法getReturnTypeByClass()以获取returnType,具体取决于收到的课程。

这将有效:

int volume = test2.getTypedValue(Function.VOLUME, "123");

这将显示编译时错误,非常容易检测和修复:

String volume = test2.getTypedValue(Function.VOLUME, "123");

最后,您可以将Function类的定义与其他类名称中的函数声明分开,例如Functions

答案 2 :(得分:0)

修改您的枚举,如下所示。

public enum ReturnType {
    NA(String.class) {
        @Override
        public String getValue(String param) {
            return param;
        }
    },
    INTEGER(Integer.class) {
        @Override
        public Integer getValue(String param) {
            return Integer.valueOf(param);
        }
    },
    JSON(JsonElement.class) {
        @Override
        public <T> T getValue(String param) {
            return null;
        }
    },
    STRING(String.class) {
        @Override
        public String getValue(String param) {
            return param;
        }
    },
    FLOAT(Float.class),
    DOUBLE(Double.class),
    IP_ADDRESS(InetAddress.class),
    UNKNOWN(String.class),
    BOOLEAN(Boolean.class);

    private Class<?> c;

    <T> ReturnType(Class<T> clazz) {
        this.c = clazz;
    }

    public Class<?> getClazz() {
        return this.c;
    }

    public abstract <T>  T getValue(String param);
}

您必须在每个ReturnType中实现以从String返回生成的T值。

然后你可以使用如下的ReturnType枚举。

public <T> T getTypedValue(String functionName, String value, Class<T> clazz) {
        ReturnType type = this.getReturnType(functionName);
        if(type.getClazz().equals(clazz)) {
           return type.getValue(value);
        }
        return null;
}

请善意忽略编译器错误,请修复它。我想给你一个实现其他方式的想法。