java方法采用T extends Number

时间:2017-12-10 20:57:18

标签: java generics

我有点生疏,陷入了一些基本问题。我希望我的方法printBinary能够接受LongInteger。并根据我想要调用相应对象的toBinaryString()方法的输入类型。

现在我知道有一些替代方法,比如方法重载,我可以创建两个方法,调用printBinary,但一个方法需要Long,另一个需要Integer。但如果我想用一种方法做到这一点我怎么能实现呢?

public static <T extends Object> void print(T arg){
    System.out.println(arg);
}

public static <T extends Number> void printBinary(T arg){
    if(arg instanceof Long){
        print(Long.toBinaryString(arg)); //this throws an error incompatible types: Number cannot be converted to long

    }else{
        print(Integer.toBinaryString(arg)); //this throws an error incompatible types: Number cannot be converted to int

    }
}

4 个答案:

答案 0 :(得分:4)

说明

你的写作

public static <T extends Number> void printBinary(T arg)

所以你声明T是扩展Number的东西。非常重要,请注意关于T的更多信息。所以你只能安全地假设它是Number,但仅此而已(没有检查,例如使用instanceof)。

接下来就是你写

// requires long
print(Long.toBinaryString(arg));
// requires int
print(Integer.toBinaryString(arg));

但这两种方法都不需要Number,它们需要longint。请查看他们的文档(LongInteger)。

即使我们考虑装箱,Java也只能将Long转换为longInteger转换为int(反之亦然)。但不是NumberLongNumberIntegerNumber不一定是LongInteger。例如,它也可以是Double。而且你不知道T是什么,你只知道它至少是Number类型。

效用方法

因此,您需要做的是明确arg转换为longint。因此,您可以使用Number提供的实用程序方法,即Number#longValueNumber#intValue

print(Long.toBinaryString(arg.longValue()));
print(Integer.toBinaryString(arg.intValue()));

instanceof

之后进行投射

另一个可能是施放他们。如果您使用instanceof检查T确实属于Long类型或Integer,则可以安全地投放它:

print(Long.toBinaryString((Long) arg));
print(Integer.toBinaryString((Integer) arg));

投射后,Java会自动将Long转换为long,将Integer转换为int,这称为取消装箱。或者为了使其更明确,请自行调用取消装箱方法:

print(Long.toBinaryString(((Long) arg).longValue()));
print(Integer.toBinaryString(((Integer) arg).intValue()));

备注

准确地说,使用您当前的代码,取消选中 <{1}}。您还需要检查Integer,因此更安全:

arg instanceof Integer

答案 1 :(得分:2)

如果你想要你的方法

public static <T extends Number> void printBinary(T arg){
    if(arg instanceof Long){
        print(Long.toBinaryString(arg)); //this throws an error incompatible types: Number cannot be converted to long

    }else{
        print(Integer.toBinaryString(arg)); //this throws an error incompatible types: Number cannot be converted to int

    }
}

要工作,你需要在调用toBinaryString(art)方法时使用强制转换,例如像这样

public static <T extends Number> void printBinary(T arg){
    if(arg instanceof Long){
        print(Long.toBinaryString((Long) arg)); //this throws an error incompatible types: Number cannot be converted to long

    }else{
        print(Integer.toBinaryString((Integer) arg)); //this throws an error incompatible types: Number cannot be converted to int

    }
}

但是,您发布的代码仍存在一个问题。正如@Jacob H所说,像<T extends Number>这样的声明意味着该方法将接受扩展Number类的任何类的参数。因此,如果参数的类型为Integer或Long,它将起作用,但是例如Float值将被传递时将失败。 很遗憾toBinaryString方法不是由Number类实现的,而是由Integer和Long之类的子类提供的方法。 因此,对于您的情况,实现两个采用不同类型参数的分离方法可能更好 - Long和Integer。 如果你真的想使用这种通用符号,但不处理除Integer和Long之外的其他类型的输入,你可能需要生成某种参数类型验证。但是,仍然,定义采用Number类型参数并且不处理它的某些子类的方法,有些确实可能会让人感到困惑并且看起来像是一个糟糕的设计。

答案 2 :(得分:0)

您只想使用<Number><T extends Number>表示“某些类型T扩展数字”,因此它需要Long或Integer,但不能同时使用。 <Number>表示“数字或任何扩展数字的类型”

答案 3 :(得分:0)

最好的解决方案是使用方法过载。使用Number,该方法也将接受双打。

如果您真的想使用Number,则不需要泛型。重写像这样的方法

public static void print(Object arg)

public static void printBinary(Number arg)