Em Java, eu gostaria de ter algo como:
class Clazz<T> {
static void doIt(T object) {
// ...
}
}
Mas eu entendo
Não é possível fazer uma referência estática para o tipo não estático T
Eu não entendo genéricos além dos usos básicos e, portanto, não consigo entender muito isso. Não ajuda que eu não tenha conseguido encontrar muita informação na internet sobre o assunto.
Alguém poderia esclarecer se esse uso é possível, de maneira semelhante? Além disso, por que minha tentativa original não teve êxito?
fonte
Java não sabe o que
T
é até você instanciar um tipo.Talvez você possa executar métodos estáticos chamando,
Clazz<T>.doit(something)
mas parece que não pode.A outra maneira de lidar com as coisas é colocar o parâmetro type no próprio método:
o que não lhe dá a restrição certa em U, mas é melhor que nada ....
fonte
Eu encontrei esse mesmo problema. Encontrei minha resposta baixando o código-fonte
Collections.sort
no framework java. A resposta que usei foi colocar o<T>
genérico no método, não na definição de classe.Então, isso funcionou:
Obviamente, depois de ler as respostas acima, percebi que essa seria uma alternativa aceitável sem o uso de uma classe genérica:
fonte
T extends XXX
sintaxe.Comparable
. Tente em<T extends Comparable<? super T>>
vez disso.É possível fazer o que você deseja usando a sintaxe para métodos genéricos ao declarar seu
doIt()
método (observe a adição de<T>
entrestatic
evoid
na assinatura do métododoIt()
):Eu obtive o editor Eclipse para aceitar o código acima sem o
Cannot make a static reference to the non-static type T
erro e o expandi para o seguinte programa de trabalho (completo com uma referência cultural apropriada para a idade):Que imprime essas linhas no console quando eu o executo:
fonte
<T>
mascara o primeiro da mesma maneira que noclass C { int x; C(int x) { ... } }
parâmetrox
mascara o campox
.static <E extends SomeClass> E foo(E input){return input;}
para todos e cada método quando eu gostaria de fazer algo assimstatic <E extends SomeClass>; //static generic type defined only once and reused
static E foo(E input){return input;}
static E bar(E input){return input;}
//...etc...
Eu acho que essa sintaxe ainda não foi mencionada (no caso de você querer um método sem argumentos):
E a ligação:
Espero que isso ajude alguém.
fonte
<String>
porque simplesmente infere o argumento de tipo porque você o atribui a uma variável. Se você não atribuir, simplesmente deduzObject
.É corretamente mencionado no erro: você não pode fazer uma referência estática para o tipo não estático T. O motivo é que o parâmetro type
T
pode ser substituído por qualquer um dos argumentos de tipo, por exemplo,Clazz<String>
ouClazz<integer>
etc. Mas os campos / métodos estáticos são compartilhados por todos os objetos estáticos da classe.O seguinte trecho é retirado do documento :
Como corretamente apontado por chris em sua resposta, você precisa usar o parâmetro type com o método e não com a classe neste caso. Você pode escrever como:
fonte
Algo como o seguinte o aproximaria
EDIT: Exemplo atualizado com mais detalhes
fonte
Quando você especifica um tipo genérico para sua classe, a JVM sabe que ela possui apenas uma instância da sua classe, não uma definição. Cada definição possui apenas um tipo parametrizado.
Os genéricos funcionam como modelos em C ++; portanto, você deve instanciar sua classe primeiro e depois usar a função com o tipo especificado.
fonte
Clazz<int>::doIt( 5 )
)Também para simplificar, isso acontece devido à propriedade "Erasure" dos genéricos. O que significa que, embora definamos
ArrayList<Integer>
eArrayList<String>
, no tempo de compilação, ele permanece como dois tipos concretos diferentes, mas no tempo de execução a JVM apaga tipos genéricos e cria apenas uma classe ArrayList em vez de duas classes. Portanto, quando definimos um método de tipo estático ou qualquer coisa para um genérico, ele é compartilhado por todas as instâncias desse genérico, no meu exemplo, é compartilhado por ambosArrayList<Integer>
eArrayList<String>
. É por isso que você recebe o erro. Permitido em um contexto estático!fonte
@BD em Rivenhill: Como essa pergunta antiga ganhou atenção renovada no ano passado, vamos continuar um pouco, apenas por uma questão de discussão. O corpo do seu
doIt
método não faz nadaT
específico. Aqui está:Então você pode descartar inteiramente todas as variáveis de tipo e apenas codificar
Está bem. Mas vamos voltar mais perto do problema original. A primeira variável de tipo na declaração de classe é redundante. Somente o segundo no método é necessário. Aqui vamos nós novamente, mas ainda não é a resposta final:
No entanto, é muito barulho por nada, já que a versão a seguir funciona da mesma maneira. Tudo o que precisa é do tipo de interface no parâmetro method. Não há variáveis de tipo à vista em qualquer lugar. Esse era realmente o problema original?
fonte
Como as variáveis estáticas são compartilhadas por todas as instâncias da classe. Por exemplo, se você está tendo o seguinte código
T está disponível somente após a criação de uma instância. Mas métodos estáticos podem ser usados mesmo antes que as instâncias estejam disponíveis. Portanto, parâmetros do tipo genérico não podem ser referenciados dentro de métodos e variáveis estáticos
fonte