Статический метод в универсальном классе?



в Java, я хотел бы иметь что-то как:



class Clazz<T> {
static void doIt(T object) {
// shake that booty
}
}


но я



Cannot make a static reference to the non-static type T


Я не понимаю дженерики за пределами основных применений и, следовательно, не могу понять этого. Это не помогает, что я не смог найти много информации в интернете по этому вопросу.



может ли кто-нибудь уточнить, возможно ли такое использование, аналогичным образом? Кроме того, почему моя первоначальная попытка оказалась неудачной?

691   12  

12 ответов:

вы не можете использовать параметры универсального типа класса в статических методах или статических полях. Параметры типа класса находятся только в области видимости для методов экземпляра и полей экземпляра. Для статических полей и статических методов они являются общими для всех экземпляров класса, даже для экземпляров различных параметров типа, поэтому очевидно, что они не могут зависеть от конкретного параметра типа.

не похоже, что ваша проблема должна требовать использования параметра типа класса. Если вы опишете то, что вы пытаетесь сделать более подробно, может быть, мы можем помочь вам найти лучший способ сделать это.

Java не знает, что T до тех пор, пока вы не создадите экземпляр типа.

возможно, вы можете выполнить статические методы, вызвав Clazz<T>.doit(something) но это звучит так, как будто вы не можете.

другой способ обработки вещей-это поместить параметр типа в сам метод:

static <U> void doIt(U object)

что не дает вам правильного ограничения на U, но это лучше, чем ничего....

я столкнулся с этой же проблемой. Я нашел свой ответ, загрузив исходный код для Collections.sort в рамках java. Ответ, который я использовал, был поставить <T> generic в методе, а не в определении класса.

так это работает:

public class QuickSortArray  {
    public static <T extends Comparable> void quickSort(T[] array, int bottom, int top){
//do it
}

}

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

public static void quickSort(Comparable[] array, int bottom, int top){
//do it
}

можно делать то, что вы хотите, используя синтаксис для универсальных методов при объявлении вашего doIt() способ (обратите внимание на добавление <T> между static и void в сигнатуре метода doIt()):

class Clazz<T> {
  static <T> void doIt(T object) {
    // shake that booty
  }
}

я получил редактор Eclipse, чтобы принять приведенный выше код без Cannot make a static reference to the non-static type T ошибка, а затем расширил его до следующей рабочей программы (в комплекте с несколько соответствующей возрасту культурной ссылкой):

public class Clazz<T> {
  static <T> void doIt(T object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }

  private static class KC {
  }

  private static class SunshineBand {
  }

  public static void main(String args[]) {
    KC kc = new KC();
    SunshineBand sunshineBand = new SunshineBand();
    Clazz.doIt(kc);
    Clazz.doIt(sunshineBand);
  }
}

который выводит эти строки на экран консоль, когда я запускаю его:

встряхните эту попку ' класс com.eclipseoptions.datamanager.Clazz$KC'!!!
встряхните эту попку ' класс com.eclipseoptions.datamanager.Clazz$SunshineBand'!!!

это правильно указано в ошибке: вы не можете сделать статическую ссылку на нестатический тип T. причиной является параметр типа T может быть заменен любым аргументом типа, например Clazz<String> или Clazz<integer> etc. Но статические поля/методы являются общими для всех нестатических объектов класса.

следующий отрывок взят из doc:

статическое поле класса-это переменная уровня класса, общая для всех нестатические объекты класс. Следовательно, статические поля типа параметры не допускаются. Рассмотрим следующий класс:

public class MobileDevice<T> {
    private static T os;

    // ...
}

если бы статические поля параметров типа были разрешены, то следующий код был бы перепутан:

MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();

поскольку ОС статического поля совместно используется телефоном, пейджером и ПК, каков фактический тип ОС? Это не может быть смартфон, пейджер, и TabletPC в то же время. Поэтому вы не можете создавать статические поля типа параметры.

как справедливо указал Крис в своем ответ в этом случае вам нужно использовать параметр типа с методом, а не с классом. Вы можете написать это так:

static <E> void doIt(E object) 

Я думаю, что этот синтаксис еще не упоминалось (в случае, если вы хотите метод без аргументов) :

class Clazz {
  static <T> T doIt() {
    // shake that booty
  }
}

и звонок :

String str = Clazz.<String>doIt();

надеюсь, что это поможет кому-то.

другие уже ответили на ваш вопрос, но кроме того, я могу полностью рекомендовать O'Reilly Java Generics книги. Время от времени это тонкий и сложный предмет, и если часто кажется, что у него есть бессмысленные ограничения, но книга делает довольно хорошую работу по объяснению того, почему генераторы java такие, какие они есть.

что-то вроде следующего приблизит вас

class Clazz
{
   public static <U extends Clazz> void doIt(U thing)
   {
   }
}

изменить: обновленный пример с более подробной информацией

public abstract class Thingo 
{

    public static <U extends Thingo> void doIt(U p_thingo)
    {
        p_thingo.thing();
    }

    protected abstract void thing();

}

class SubThingoOne extends Thingo
{
    @Override
    protected void thing() 
    {
        System.out.println("SubThingoOne");
    }
}

class SubThingoTwo extends Thingo
{

    @Override
    protected void thing() 
    {
        System.out.println("SuThingoTwo");
    }

}

public class ThingoTest 
{

    @Test
    public void test() 
    {
        Thingo t1 = new SubThingoOne();
        Thingo t2 = new SubThingoTwo();

        Thingo.doIt(t1);
        Thingo.doIt(t2);

        // compile error -->  Thingo.doIt(new Object());
    }
}

когда вы указываете универсальный тип для своего класса, JVM знает об этом только с экземпляром вашего класса, а не с определением. Каждое определение имеет только параметризованный тип.

дженерики работают как шаблоны в C++, поэтому вы должны сначала создать экземпляр своего класса, а затем использовать функцию с указанным типом.

также говоря простыми словами, это происходит из-за свойства "стирания" дженериков.Это означает, что хотя мы определяем ArrayList<Integer> и ArrayList<String>, во время компиляции он остается как два разных конкретных типа, но во время выполнения JVM стирает универсальные типы и создает только один класс ArrayList вместо двух классов. Поэтому, когда мы определяем метод статического типа или что-либо для универсального, он совместно используется всеми экземплярами этого универсального, в моем примере он совместно используется обоими ArrayList<Integer> и ArrayList<String> .Вот почему вы получаете ошибку.Параметр универсального типа класса не допускается в статическом контексте!

@BD at Rivenhill: поскольку этот старый вопрос получил новое внимание в прошлом году, давайте немного продолжим, просто ради обсуждения. Тело вашего doIt метод ничего не делает Tу всех. Вот это:

public class Clazz<T> {
  static <T> void doIt(T object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }
// ...
}

таким образом, вы можете полностью удалить все переменные типа и просто код

public class Clazz {
  static void doIt(Object object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }
// ...
}

ОК. Но давайте вернемся ближе к исходной проблеме. Первая переменная типа в объявлении класса является избыточной. Только второй по счету метод необходим. Здесь мы снова идем, но это еще не окончательный ответ:

public class Clazz  {
  static <T extends Saying> void doIt(T object) {
    System.out.println("shake that booty "+ object.say());
  }

  public static void main(String args[]) {
    Clazz.doIt(new KC());
    Clazz.doIt(new SunshineBand());
  }
}
// Output:
// KC
// Sunshine

interface Saying {
      public String say();
}

class KC implements Saying {
      public String say() {
          return "KC";
      }
}

class SunshineBand implements Saying {
      public String say() {
          return "Sunshine";
      }
}

однако, это все слишком много суеты ни о чем, так как следующая версия работает точно так же. Все, что ему нужно, это тип интерфейса в параметре метода. Нигде не видно переменных типа. Это действительно была первоначальная проблема?

public class Clazz  {
  static void doIt(Saying object) {
    System.out.println("shake that booty "+ object.say());
  }

  public static void main(String args[]) {
    Clazz.doIt(new KC());
    Clazz.doIt(new SunshineBand());
  }
}

interface Saying {
      public String say();
}

class KC implements Saying {
      public String say() {
          return "KC";
      }
}

class SunshineBand implements Saying {
      public String say() {
          return "Sunshine";
      }
}

поскольку статические переменные являются общими для всех экземпляров класса. Например, если у вас есть следующий код

class Class<T> {
  static void doIt(T object) {
    // using T here 
  }
}

T доступно только после создания экземпляра. Но статические методы могут использоваться даже до того, как будут доступны экземпляры. Таким образом, параметры универсального типа не могут ссылаться внутри статических методов и переменных

Comments

    Ничего не найдено.