Java泛型和数值类型

Java泛型和数值类型,java,generics,Java,Generics,我想创建一个通用方法,它可以有效地执行以下操作: class MyClass { static <T extends Number> T sloppyParseNumber(String str) { try { return T.valueOf(str); } catch (Exception e) { return (T)0; } } } 用Java实现上述通用方法

我想创建一个通用方法,它可以有效地执行以下操作:

class MyClass {

    static <T extends Number> T sloppyParseNumber(String str) {
        try {
            return T.valueOf(str);
        } catch (Exception e) {
            return (T)0;
        }
    }
}
用Java实现上述通用方法可行吗?如果是,如何进行?如果没有,什么是好的替代方法



编辑:似乎有一些可能的重复,但我没有找到一个,这正好涵盖了这一点。我希望有一些技巧可以使用,这将允许这两个操作:将字符串解析为
Number
子类,并为
Number
子类返回0值。

Java泛型只提供编译时检查,编译后类型信息几乎被丢弃。因此,Java中不可能使用
T.valueOf
语句。解决方案是按照评论中已经提到的详细方式进行。还有,既然您在编译时指定了类型,那么您为什么要执行
MyClass.sloppyParseNumber(value)
,而不执行
MyClass.sloppyParseDouble(value)
Number
Number
没有
valueOf
方法,您所追求的方法不起作用

最简单的方法就是创建一些静态方法,比如
sloppyParseInt
sloppyParseFloat
,等等

您可以这样做,但我不确定我是否喜欢,并且可能会在以下方面有所改进:

public class Main 
{
    private static final Map<Class<? extends Number>, NumberConverter> CONVERTERS;

    static
    {
        CONVERTERS = new HashMap<>();
        CONVERTERS.put(Integer.class, new IntegerConverter());
    }

    public static void main(String[] args) 
    {
        Number valueA;
        Number valueB;

        valueA = CONVERTERS.get(Integer.class).convert("42");
        valueB = CONVERTERS.get(Integer.class).convert("Hello, World!");

        System.out.println(valueA);
        System.out.println(valueB);
    }
}

interface NumberConverter<T extends Number>
{
    T convert(String str);
}

class IntegerConverter
    implements NumberConverter<Integer>
{
    @Override
    public Integer convert(String str) 
    {
        try
        {
            return Integer.valueOf(str);
        } 
        catch (NumberFormatException ex) 
        {
            return 0;
        }    
    }
}
公共类主
{

私有静态最终地图我100%同意TofuBeer。但如果为了时间起见您希望避免冗长,这也应该做到:

static <T extends Number> T sloppyParseNumber(String str,Class<T> clas) {

    if (clas == null) throw new NullPointerException("clas is null");

    try {

        if(clas.equals(Integer.class)) {
            return (T) Integer.valueOf(str);
        }
        else if(clas.equals(Double.class)) {
            return (T) Double.valueOf(str);
        }
        //so on

    catch(NumberFormatException|NullPointerException ex) {
        // force call with valid arguments
        return sloppyParseNumber("0", clas);
    }

    throw new IllegalArgumentException("Invalid clas " + clas);

}
static T sloppyParseNumber(字符串str,类clas){
如果(clas==null)抛出新的NullPointerException(“clas为null”);
试一试{
if(类等于(整数类)){
返回(T)整数。值为(str);
}
else if(类等于(双类)){
返回值(T)加倍。值(str);
}
//诸如此类
catch(NumberFormatException | NullPointerException ex){
//带有效参数的强制调用
返回sloppyParseNumber(“0”,clas);
}
抛出新的IllegalArgumentException(“无效clas”+clas);
}

但是纯粹从
T
,您无法在运行时获取类型。

因此,我决定采用另一种方法:

static String trimTo0(String str) {
    if (str == null) return "0";
    str = str.trim();
    if (str.isEmpty()) return "0";
    return str;
}
用法:

String value = null;
System.out println("Double value: " + Double.parseDouble(trimTo0(value)));
请注意,这比问题中的方法更为有限,它不会将无效的非数字字符串转换为
“0”
。完全这样做需要两个单独的方法,一个支持小数点,另一个仅支持整数。

您可以尝试以下方法:

private <T> T convertToType(Class<T> clazz,String str) throws Exception {
    return clazz.getConstructor(String.class).newInstance(str);
}
private T convertToType(类clazz,字符串str)引发异常{
返回clazz.getConstructor(String.class).newInstance(str);
}

这里,您需要考虑的是,该类型必须具有一个字符串参数的构造函数。

抽象类不包含任何将字符串解析为一个类型的方法,因为解析是由特定类型完成的。建议不要使用泛型,而是创建函数如<代码>…to整型< /COD>,<代码>……双/<代码>等等。我不认为有一个简单的方法可以做到这一点。我只需要使用像
newmyclass(value).asDouble();
这样的东西,并实现
asInteger
asLong
asFloat
asDouble
等。手动方法
t.valueOf()
即使有一个静态方法
Number.valueOf(),也不起作用
;您不能像这样使用泛型类型。这可能是的重复。我认为更好的API应该是调用
NumberConvert.convert(Integer.class,string)
,并在内部处理细节。@hyde:我不确定我是否理解。当您说“它的功能与往常一样,指定类型不起任何作用",为什么您认为指定类型没有任何作用?在您更新的示例中,
slopyParseNumber
的返回类型是什么?它如何知道传入的数字是否应该被解析为
BigDecimal
Double
Float
Integer
等?让我们再试一次:MyClass.slopp的目的yParseNumber将使方法返回双对象,但实际上Java泛型并不是这样工作的,方法无法知道调用方在
中指定的类型。这似乎是最接近我在问题中提出的方法,尽管我仍然希望您的答案包括捕获异常并返回e right子类(因此返回
T
并具有
类clas
参数,我猜)。
private <T> T convertToType(Class<T> clazz,String str) throws Exception {
    return clazz.getConstructor(String.class).newInstance(str);
}