类型转换和泛型
Typecasting and Generics
我正在开发一个消息解析库,其中消息正文在每种情况下都以字符串形式返回。我想创建一个函数,自动将该结果转换为正确的类型,但我不确定是否可行。
我的结构是这样的:
我有一个名为 ReturnType 的枚举。这包含这包含 return 类型的 class 变量。
我有一个函数映射,它将用户尝试调用的函数映射到 return 类型的消息响应。
我想我已经在某种程度上工作了,但问题是我必须将我想要的 class 包含在 getTypedValue() 方法调用中,我认为这是多余的,因为我已经知道 return 类型基于函数映射中的 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()+")");
}
}
以下是用户调用获取输入值的方式。为了简化,我输入了一个静态值 (15),但这实际上是一个从消息响应中获取结果的方法调用:
Integer volume = fm.getTypedValue("VOLUME", "15", Integer.class);
有没有办法在不提供 class 的情况下使其 return 成为正确的类型?即
Integer volume = fm.getTypedValue("VOLUME", "15");
Double minutes = fm.getTypedValue("MINUTES", "15.25");
Boolean isRunning = fm.getTypedValue("IS_RUNNING","true");
我不确定是否可行,即使可行,我认为我目前拥有的代码可能有点丑陋且难以理解。
遗憾的是,没有办法。编译器期望类型在运行时丢失,这使得将它分配给 Object
以外的任何东西都不安全
或者,您可以 return 一个 Object
并进行多次 instanceof
检查,但我认为那更糟。
另一种方法是使用提供的泛型调用方法。不幸的是,我不确定这是否会导致其他编译错误。试试
Double minutes = fm.<Double>getTypedValue("MINUTES", "15.25");
向泛型方法提供 Class
实例没有错,我在许多不同的库中都看到过这样的情况。
您可以做到这一点,但您将失去编译器为您提供的优势,即在编译时检查类型是否正确。
使用类似于 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 cannot be cast to java.lang.String
如果您想要可能 不太容易出错的东西(在编译时而不是运行时显示错误),您可以在 handle/know/provide 中定义所有函数class(枚举不处理泛型)。
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
}
您可以根据收到的 class 创建方法 getReturnTypeByClass()
来获取 returnType
。
这会起作用:
int volume = test2.getTypedValue(Function.VOLUME, "123");
这将显示编译时错误,非常容易检测和修复:
String volume = test2.getTypedValue(Function.VOLUME, "123");
最后,您可以将 Function
class 的定义和另一个 class 名称中的函数声明分开,例如 Functions
.
如下修改枚举。
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 中实现 return 从 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;
}
请忽略编译器错误并修复它。我想给你一个想法来实现其他方式。
我正在开发一个消息解析库,其中消息正文在每种情况下都以字符串形式返回。我想创建一个函数,自动将该结果转换为正确的类型,但我不确定是否可行。
我的结构是这样的: 我有一个名为 ReturnType 的枚举。这包含这包含 return 类型的 class 变量。
我有一个函数映射,它将用户尝试调用的函数映射到 return 类型的消息响应。
我想我已经在某种程度上工作了,但问题是我必须将我想要的 class 包含在 getTypedValue() 方法调用中,我认为这是多余的,因为我已经知道 return 类型基于函数映射中的 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()+")");
}
}
以下是用户调用获取输入值的方式。为了简化,我输入了一个静态值 (15),但这实际上是一个从消息响应中获取结果的方法调用:
Integer volume = fm.getTypedValue("VOLUME", "15", Integer.class);
有没有办法在不提供 class 的情况下使其 return 成为正确的类型?即
Integer volume = fm.getTypedValue("VOLUME", "15");
Double minutes = fm.getTypedValue("MINUTES", "15.25");
Boolean isRunning = fm.getTypedValue("IS_RUNNING","true");
我不确定是否可行,即使可行,我认为我目前拥有的代码可能有点丑陋且难以理解。
遗憾的是,没有办法。编译器期望类型在运行时丢失,这使得将它分配给 Object
或者,您可以 return 一个 Object
并进行多次 instanceof
检查,但我认为那更糟。
另一种方法是使用提供的泛型调用方法。不幸的是,我不确定这是否会导致其他编译错误。试试
Double minutes = fm.<Double>getTypedValue("MINUTES", "15.25");
向泛型方法提供 Class
实例没有错,我在许多不同的库中都看到过这样的情况。
您可以做到这一点,但您将失去编译器为您提供的优势,即在编译时检查类型是否正确。
使用类似于 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 cannot be cast to java.lang.String
如果您想要可能 不太容易出错的东西(在编译时而不是运行时显示错误),您可以在 handle/know/provide 中定义所有函数class(枚举不处理泛型)。
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
}
您可以根据收到的 class 创建方法 getReturnTypeByClass()
来获取 returnType
。
这会起作用:
int volume = test2.getTypedValue(Function.VOLUME, "123");
这将显示编译时错误,非常容易检测和修复:
String volume = test2.getTypedValue(Function.VOLUME, "123");
最后,您可以将 Function
class 的定义和另一个 class 名称中的函数声明分开,例如 Functions
.
如下修改枚举。
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 中实现 return 从 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;
}
请忽略编译器错误并修复它。我想给你一个想法来实现其他方式。