我正在尝试做这样的事情:
class MyClass<T extends Number> {
T value;
NumberFormat formatter = NumberFormat.getInstance();
public void setValueFromString(String s) {
try {
value = formatter.parse(s).doubleValue();
} catch (ParseException e) { }
}
}
当然,doubleValue()
并不总是正确使用的方法 - 例如,如果T
是Integer
,我想使用intValue()
。到目前为止,我发现处理这个问题的唯一方法是使setValueFromString()
方法抽象化,并且只在指定了T
时才在子类中定义它。
有没有办法在通用类中定义setValueFromString()
方法,用于测试T
并从Number
中选择适当的转换方法?我尝试了instanceof
,Class.isInstance()
和Class.isAssignableFrom()
,但没有一个有效,给出了关于不允许以这种方式使用T
的编译时错误。
答案 0 :(得分:3)
尝试在运行时从Generics推断出这样的东西,并根据该信息分支逻辑只是一条痛苦的道路,使你的代码非常难以理解,更容易破解。
您尝试做的更像是类型系统的滥用而不是利用它。只要您使用instanceof
或.getClass()
或任何TypeToken
魔法进行测试,您就可能做错了,特别是对于能够没有那么多的傻瓜就完成了。
只有那么多Number
个子类,只需对它们进行硬编码并将它们链接起来,其中Converter
的第一个非空返回值是合适的类型。
Guava有一些名为Converter
的东西只是为了这样的事情。
final static ShortConverter sc = new ShortConverter();
final static IntegerConverter ic = new IntegerConverter();
final static DoubleConverter dc = new DoubleConverter();
public static void main(String[] args) throws ParseException
{
System.out.println("getNumber(\"1\").getClass().toString() = " + getNumber("1").getClass().toString());
System.out.println("getNumber(\"64000\").getClass().toString() = " + getNumber("64000").getClass().toString());
System.out.println("getNumber(\"3.14\").getClass().toString() = " + getNumber("3.14").getClass().toString());
}
public static Number getNumber(@Nonnull final String s)
{
/* nest the firstNonNull() as deeply as you need for the limited
number of types */
return firstNonNull(sc.doForward(s), firstNonNull(ic.doForward(s), dc.doForward(s)));
}
public static class DoubleConverter extends Converter<String, Double>
{
@Override
protected String doBackward(@Nonnull final Double d) { return d.toString(); }
@Override
protected Double doForward(@Nonnull final String s) { return Doubles.tryParse(s); }
}
public static class IntegerConverter extends Converter<String, Integer>
{
@Override
protected String doBackward(@Nonnull final Integer i) { return i.toString(); }
@Override
protected Integer doForward(@Nonnull final String s) { return Ints.tryParse(s); }
}
public static class ShortConverter extends Converter<String, Short>
{
@Override
protected String doBackward(@Nonnull final Short s) { return s.toString(); }
@Override
protected Short doForward(@Nonnull final String s) { try { return Short.parseShort(s); } catch (NumberFormatException e) { return null; } }
}
getNumber("1").getClass().toString() = class java.lang.Short
getNumber("64000").getClass().toString() = class java.lang.Integer
getNumber("3.14").getClass().toString() = class java.lang.Double
public class MyClass<T extends Number>
{
T value;
final Converter<String,T> converter;
public MyClass(final Converter<String,T> c)
{
this.converter = c;
}
public void setValueFromString(String s)
{
this.value = this.converter.doForward(s);
}
}