静态通用方法

时间:2016-10-04 10:03:47

标签: java generics

你能解释为什么以下有效吗?

public class GenericsTest<T> {

    public void doSomething(T v1, T v2) {

    }

    public static <T> void doSomethingStatic(T v1, T v2) {

    }

    public static <T> void doSomethingStaticList(List<T> v1, List<T> v2)
    {

    }

    public static void main(String[] args) {
        GenericsTest<String> gt = new GenericsTest<>();

        // OK
        gt.doSomething("abc", "abc");

        // Not OK
        gt.doSomething(1, "abc");

        // OK
        doSomethingStatic(1, 2);

        // Still OK
        doSomethingStatic(1, "abc");

        // So why is this not OK?
        List<String> list1=new LinkedList<>();
        List<Integer> list2=new LinkedList<>();
        doSomethingStaticList(list1,list2);
    }
}

T v1, T v2应该是doSomethingStatic中的相同类型,但我仍然可以传递不同的类型(整数和字符串)。

如果doSomethingStatic()默认采用普通超类,为什么doSomethingStaticList()不能使用不同的类型?

4 个答案:

答案 0 :(得分:23)

在非静态情况下,您在创建T的实例时将String定义为GenericsTest。因此传递int将导致编译错误。如果你做gt.doSomething(1, 2)它也会失败。

在静态情况下,您不手动定义T,它是从参数派生的。它将是这两个类的第一个常见超类 - 在本例中为Object。您可能希望使用有界通配符,例如<T extends Number><T extends CharSequence>

请注意,您在这里有两个不同的T

  • GenericsTest<T>
  • public static <T> void doSomethingStatic(T v1, T v2)

泛型参数的声明是在您编写<T>时。在这种情况下,您可以使用不同的字母以避免混淆。

答案 1 :(得分:14)

这是有效的,因为静态方法中的T自己的类型参数,而不是实例T参数。 strong>成员方法。重命名以澄清:

public static class GenericsTest<T> {

    public void doSomething(T v1, T v2) {

    }

    public static <V> void doSomethingStatic(V v1, V v2) {

    }
//...

因此,如果doSomething(...)您的实例类型参数值为String,那么这是一个错误。如果类型参数的静态doSomethingStatic(...)值不同:

GenericsTest.doSomethingStatic(1, "abc"); //ok
GenericsTest.<Object>doSomethingStatic(1, "abc"); //ok
GenericsTest.<String>doSomethingStatic(1, "abc"); //not ok
new GenericsTest<String>().doSomething(1, "abc"); //not ok

答案 2 :(得分:2)

首先是一点理论:

发生了什么:

  • 当泛型表达式在返回值之前时,则新的泛型类型变量被“声明”。因此,类声明的T与方法声明的T不同(对于编译器而言)。
  • 编译器应用类型推断,在您的示例中,它确定应用方法调用的合适类型是Object

您可以在没有静态方法的情况下尝试此示例:

public class GenericsTest<T> {

  public void doSomething(T v1, T v2) {

  }

  public <T> void doSomething2(T v1, T v2) {

  }

  public static void main(String[] args) {
    GenericsTest<String> gt = new GenericsTest<>();

    // ok
    gt.doSomething("abc", "abc");

    // Not ok
    gt.doSomething(1, "abc");

    // ok
    gt.doSomething2(1, 2);

    // Still ok
    gt.doSomething2(1, "abc");

  }

}

答案 3 :(得分:0)

在静态情况下,您不手动定义T,它是从参数派生的。 在doSomethingStaticList(list1,list2)的情况下,其中list1是String泛型List而list2是Integer泛型List。编译器推断算法将无法识别,因为列表和列表不属于任何常见类型。