Подтвердить что ты не робот

Статические общие методы

Можете ли вы объяснить, почему работает следующее?

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, но я все еще могу передавать разные типы (integer и string).

Если doSomethingStatic() по умолчанию использует общий суперкласс, почему doSomethingStaticList() не работает с разными типами?

4b9b3361

Ответ 1

В нестатистическом случае вы определяете 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>. Вы можете использовать разные буквы в этом случае, чтобы избежать путаницы.

Ответ 2

Это работает, потому что T в вашем статическом методе - это его тип собственный, а не параметр T для экземпляра, который используется в вашем методе . Переименуйте его, чтобы уточнить:

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

Ответ 3

Сначала немного теории:

  • Общие методы - это методы, которые вводят свои собственные параметры типа Учебники по Java - общие методы
  • Вывод типа - это способность компилятора Java, чтобы посмотреть на каждый вызов метода и соответствующее объявление, чтобы определить аргумент типа (или аргументы), который делает обращение применимым Java Tutorials - Тип ввода

Итак, что произойдет:

  • когда общее выражение предшествует возвращаемому значению, тогда объявляется новая универсальная переменная типа. Таким образом, 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");

  }

}

Ответ 4

В статическом случае вы не определяете T вручную, оно выводится из параметров. В случае doSomethingStaticList (list1, list2), где list1 является строковым списком String, а list2 является общим списком Integer. Алгоритм вывода компилятора не сможет распознать, поскольку List и List не принадлежат к общему типу.