Pergunta

Em Java, eu gostaria de ter algo como:

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

Mas eu fico

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

Eu não entendo genéricos além dos usos básicos e, portanto, não pode fazer muito sentido nisso. Não ajuda que eu não era capaz de encontrar muita informação na internet sobre o assunto.

Alguém poderia esclarecer se essa utilização for possível, de forma semelhante? Além disso, por que era a minha tentativa original mal sucedida?

Foi útil?

Solução

Você não pode usar parâmetros de tipo genérico de uma classe de métodos estáticos ou campos estáticos. parâmetros de tipo da classe são somente no escopo de métodos de instância e campos de instância. Para campos estáticos e métodos estáticos, eles são compartilhados entre todas as instâncias da classe, até mesmo instâncias de diferentes parâmetros de tipo, então obviamente eles não podem depender de um parâmetro de tipo particular.

Ele não parece ser o problema deve exigir o uso de parâmetro de tipo da classe. Se você descrever o que você está tentando fazer com mais detalhes, talvez possamos ajudá-lo a encontrar uma maneira melhor de fazê-lo.

Outras dicas

Java não sabe o que T é até que você instanciar um tipo.

Talvez você possa executar métodos estáticos chamando Clazz<T>.doit(something) mas parece que você não pode.

A outra maneira de lidar com as coisas é colocar o parâmetro de tipo no método próprio:

static <U> void doIt(U object)

que não levá-lo a restrição direito em U, mas é melhor do que nada ....

Corri para este mesmo problema. Eu encontrei a minha resposta fazendo o download do código-fonte para Collections.sort no âmbito java. A resposta que eu usei foi para colocar o <T> genérico no método, não na definição de classe.

Então, isso funcionou:

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

}

É claro que, depois de ler as respostas acima, percebi que esta seria uma alternativa aceitável sem o uso de uma classe genérica:

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

É possível fazer o que quiser usando a sintaxe para métodos genéricos ao declarar seu método doIt() (aviso a adição de <T> entre static e void na assinatura do método de doIt()):

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

Eu tenho editor Eclipse para aceitar o código acima, sem o erro Cannot make a static reference to the non-static type T e depois expandiu para o seguinte programa de trabalho (completo com referência cultural pouco apropriado para a idade):

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

que imprime estas linhas para o console quando eu executá-lo:

agitação que montante 'classe com.eclipseoptions.datamanager.Clazz $ KC' !!!
agite esse montante 'classe com.eclipseoptions.datamanager.Clazz $ SunshineBand' !!!

Eu acho que esta sintaxe ainda não foi mencionada (no caso você quer um método sem argumentos):

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

E a chamada:

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

Espero que isso ajuda alguém.

Ele está correctamente mencionado no erro: você não pode fazer uma referência estática para tipo T. non-static A razão é a T tipo de parâmetro pode ser substituído por qualquer um dos argumentos de tipo por exemplo campos Clazz<String> ou Clazz<integer> etc. Mas estáticas / métodos são compartilhados por todos os objetos não estáticos da classe.

O seguinte excerto é retirado do doc :

campo estático de uma classe é uma variável de nível de classe compartilhada por todos non-static objetos da classe. Assim, estática campos do tipo parâmetros não são permitidos. Considere a seguinte classe:

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

    // ...
}

Se campos estáticos de parâmetros de tipo foram autorizados, em seguida, o código a seguir ser confundido:

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

porque o sistema operacional campo estático é compartilhado por telefone, pager, e pc, o que é o tipo real do sistema operacional? Não pode ser Smartphone, Pager, e TabletPC ao mesmo tempo. Você não pode, portanto, criar campos estáticos de parâmetros de tipo.

Como bem apontado por Chris em sua resposta href="https://stackoverflow.com/a/7890292"> você precisa usar parâmetro do tipo com o método e não com a classe nesta caso. Você pode escrever assim:

static <E> void doIt(E object) 

Outros têm respondido à sua pergunta já, mas, além disso posso absolutamente recomment o O'Reilly Java Generics reservar. É um assunto sutil e complexo, às vezes, e se muitas vezes parece ter restrições inúteis, mas o livro faz um trabalho muito bom de explicar por que os genéricos Java são do jeito que são.

Algo como o seguinte iria chegar mais perto

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

EDIT: Atualizado exemplo, com mais detalhes

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());
    }
}

Quando você especifica um tipo genérico para a sua classe, JVM saber sobre ele ter apenas uma instância de sua classe, não definição. Cada definição apenas tem parametrizada tipo.

Os genéricos funcionam como modelos em C ++, então você deve primeiro instanciar sua classe, em seguida, usar a função com o tipo que está sendo especificado.

Também para colocá-lo em termos simples, isso acontece por causa da propriedade "Erasure" dos meios generics.Which que, embora nós definimos ArrayList<Integer> e ArrayList<String>, no tempo de compilação permanece como dois tipos de concreto diferentes, mas no tempo de execução do JVM apaga tipos genéricos e cria apenas uma classe ArrayList em vez de duas classes. Então, quando nós definimos um método tipo estático ou qualquer coisa por um genérico, que é compartilhado por todas as instâncias do que genérica, no meu exemplo é compartilhada por ambos ArrayList<Integer> e ArrayList<String> .que é por isso que você obtenha o tipo error.A genérico de parâmetros de uma Classe não é permitido em um contexto estático!

@BD em Rivenhill: Uma vez que esta velha questão tenha chegado atenção renovada no ano passado, vamos um pouco, apenas para fins de discussão. O corpo de seu método doIt não faz específica T-nada. Aqui está:

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

Assim, você pode totalmente deixar cair todas as variáveis ??de tipo e código apenas

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

Ok. Mas vamos voltar para mais perto do problema original. A primeira variável de tipo na declaração de classe é redundante. Só é necessário o segundo no método. Aqui vamos nós de novo, mas não é a resposta final, ainda:

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

No entanto, é tudo muito barulho sobre nada, uma vez que a versão seguinte funciona exatamente da mesma maneira. Tudo que precisa é o tipo de interface no parâmetro do método. Não há variáveis ??do tipo em qualquer lugar vista. Era realmente o problema original?

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

Desde variáveis ??estáticas são compartilhados por todas as instâncias da classe. Por exemplo, se você está tendo seguinte código

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

T está disponível apenas depois que uma instância é criada. Mas os métodos estáticos pode ser usado mesmo antes de casos estão disponíveis. Assim, parâmetros de tipo genérico não pode ser referenciado dentro de métodos estáticos e variáveis ??

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top