选择基于泛型类型的方法

时间:2015-05-15 19:59:20

标签: java android

我正在尝试做这样的事情:

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()并不总是正确使用的方法 - 例如,如果TInteger,我想使用intValue()。到目前为止,我发现处理这个问题的唯一方法是使setValueFromString()方法抽象化,并且只在指定了T时才在子类中定义它。

有没有办法在通用类中定义setValueFromString()方法,用于测试T并从Number中选择适当的转换方法?我尝试了instanceofClass.isInstance()Class.isAssignableFrom(),但没有一个有效,给出了关于不允许以这种方式使用T的编译时错误。

1 个答案:

答案 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);
    }
}