为什么这种通用方法不安全?

时间:2009-08-12 20:26:48

标签: java generics warnings

以下方法会生成警告,但对我来说看起来很安全。我确定问题出在我身上:

public <S extends CharSequence> S foo(S s) {
    return (S) new StringBuilder(s);
}

看起来这总是会返回参数s。任何人都可以展示一个会导致此方法抛出异常的示例吗?

编辑:我对此处是否需要泛型的问题并不特别感兴趣。相反,我正在寻找这种方法不安全的演示。

6 个答案:

答案 0 :(得分:6)

这是不安全的,因为虽然StringBuilder是CharSequence,但它不一定是S类型(事实上,它几乎肯定不会)。只需将String传递给您的方法,就可以看到此失败。这将使用您的StringBuilder作为参数构建String,然后尝试将StringBuilder转换为String(这将失败)。

根本不需要在这里使用泛型,这应该可以正常工作:

public CharSequence foo(CharSequence s) {
    return new StringBuilder(s);
}

答案 1 :(得分:2)

例如,这将编译:

String a = foo("ss");

但它会在运行时失败:

ClassCastException: java.lang.StringBuilder cannot be cast to java.lang.String

,因为foo返回S,输入参数的类型(在这种情况下为String)。

我认为你不需要在这里使用泛型(如skaffman said in his answer):

public StringBuilder foo(CharSequence s) {
    return new StringBuilder(s);
}

答案 2 :(得分:1)

FOO( “测试”);

足以让java尝试在String中强制转换StringBuilder。

你的代码有保证是错的,你能解释一下你想要实现的目标吗?

答案 3 :(得分:1)

这里的不安全不在于方法本身(尽管它也存在问题),而是在呼叫站点。使用 S 作为输入参数的类型以及返回值告诉编译器,无论传递给函数的对象类型是什么,结果都是相同的输入(或实际上是派生类型)。

因此,允许编译器在调用

中假设
foo("hello, world")

结果将是 java.lang.String ,而在调用中

foo(new StringBuffer("hello, world"))

结果将是 StringBuffer ,依此类推。但是,在这两种情况下,您的方法都会返回它应该返回的内容,即与输入参数类型相同的对象。而是返回 StringBuilder

实际上,你的方法将使用的唯一一种输入参数是 StringBuilder ,其他任何事情迟早都会注定要与 ClassCastException 崩溃,因为编译器可能(通常会)在呼叫站点插入(隐藏)强制转换。

当然,正如其他人已经指出的那样,无论如何都不需要使用仿制药。

答案 4 :(得分:1)

方法代码的返回类型始终是StringBuilder。

这是因为表达式'new StringBuilder(x)'的声明类型总是一个StringBuilder,无论X是什么。

尝试把它投射到任何东西都是毫无意义的。 “S”信息是擦除的一部分,擦除只存在于编译时,并且在程序运行时(即运行时)被擦除。 (Casting只是一个运行时的东西,并且某些类型/类的某些类型/类已经被删除了一段运行时间,确实完全没有意义。)

答案 5 :(得分:0)

我的Java生疏了,但这种方法不会抛出任何异常

new StringBuilder(s)

可以投掷吗?