java 静态泛型方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39849482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 04:41:24  来源:igfitidea点击:

Static generic methods

javagenerics

提问by Tony

Can you explain why the following works?

你能解释为什么下面的工作?

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 v2should be the same type in doSomethingStatic, but I'm still able to pass different types(integer and string).

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

If doSomethingStatic()takes a common super class by default, why doesn't doSomethingStaticList()work with different types?

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

采纳答案by Jaroslaw Pawlak

In non-static case you define Tas Stringwhen you create instance of GenericsTest. Hence passing an intwill give compile error. If you did gt.doSomething(1, 2)it would fail as well.

在非静态情况下,您定义TString创建GenericsTest. 因此传递 anint会导致编译错误。如果你这样做,gt.doSomething(1, 2)它也会失败。

In static case, you don't define Tmanually, it is derived from parameters. It will be the first common superclass of both classes - which in this case is Object. You might want to use bounded wildcard, e.g. <T extends Number>or <T extends CharSequence>.

在静态情况下,您不T手动定义,它是从参数派生的。它将是两个类的第一个公共超类 - 在这种情况下是Object. 您可能想要使用有界通配符,例如<T extends Number><T extends CharSequence>

Note that you have two different Ts here:

请注意,这里有两个不同的Ts:

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

The declaration of generic parameter is whenever you write <T>. You can use different letters in this case to avoid confusion.

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

回答by Philip Voronov

This works because Tin your static method is his owntype parameter, not the Tparameter for instancethat used in your member method. Rename it to clarify:

这是有效的,因为T在您的静态方法中是他自己的类型参数,而不是例如在您的成员方法中使用的T参数。重命名以澄清:

public static class GenericsTest<T> {

    public void doSomething(T v1, T v2) {

    }

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

    }
//...

So in case of doSomething(...)your instance type parameter value is Stringso it's an error. In case of static doSomethingStatic(...)value of type parameter is different:

因此,如果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

回答by Aris2World

First a bit of theory:

先说点理论:

  • Generic methods are methods that introduce their own type parameters Java Tutorials - Generic Methods
  • Type inference is a Java compiler's ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable Java Tutorials - Type inference

So what happen:

那么会发生什么:

  • when a generic expression precede the return value then a new generic type variable is "declared". So the T of the class declaration is different (for the compiler) from the T of the method declaration.
  • the compiler apply type inference and in your example it determine that the suitable type to apply method invocation is Object
  • 当泛型表达式位于返回值之前时,就会“声明”一个新的泛型类型变量。所以类声明的 T 与方法声明的 T 不同(对于编译器)。
  • 编译器应用类型推断,在您的示例中,它确定应用方法调用的合适类型是 Object

You can try also this example without static method:

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

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");

  }

}

回答by Aman Goyal

In static case, you don't define T manually, it is derived from parameters. In the case doSomethingStaticList(list1,list2) where list1 is String generic List while list2 is Integer generic List. Compiler inference algorithm won't be able to recognize because List and List doesn't belong to any common type.

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