Generics - Não consigo instanciar o tipo

Ola para todos,

estou com um problema e não estou conseguindo resolver.

vejam só criei uma classe utilizando generics

public class Principal extends JPanel implements InitializingBean {

porem essa mesma classe que eu passo como parametro no generics eu quero chamar uma outra classe com um objeto do tipo E instanciado

alguem sabe me dizer como eu faço isso??

eu ja fiz instanciando um Object() com cast em E

porem tenho meu objeto tem q ser do tipo E e nao java.lang.Object

se alguem puder me ajudar.

grato

andre

Você não consegue instanciar o tipo E se não tiver um objeto do tipo Class.

Exemplo, please :slight_smile:

package exemplos;

class Pessoa {
}

class Funcionario extends Pessoa {
}

class Diretor extends Funcionario {
}

// Um exemplo bem simples...
class PlanoSaude<E> {
	E e;
	public PlanoSaude() {
		e = new E(); // Isto é inválido e provoca um erro de compilação
	}
	public PlanoSaude(Class<E> klass) throws Exception {
		e = klass.newInstance();
	}
}


public class RemedioGenerico {
	public static void main(String[] args) throws Exception {
		PlanoSaude<Diretor> psd =  new PlanoSaude<Diretor>(); // não funciona devido ao erro de compilação
		PlanoSaude<Funcionario> psf = new PlanoSaude<Funcionario>(Diretor.class); // não funciona
		PlanoSaude<Funcionario> psg = new PlanoSaude<Funcionario>(Funcionario.class); // OK
		PlanoSaude<? extends Funcionario> psh = new PlanoSaude<Diretor>(Diretor.class); // OK
	}
}

Ah, eu achei q tivesse uma forma de invocar o new com generics, da mesma forma q se pode fazer em C#

Mas valeu o exemplo!!

Esse é um dos motivos que me faz ter saudades das templates do C++…

A solução com newInstance() pode até funcionar, mas também deve disparar alguns “warnings” na sua cabeça.
Veja os problemas:

  1. O código assume que existe um construtor padrão, e que ele é suficiente;
  2. Se isso mudar, o código não dará erro de compilação, só de execução;
  3. É certamente mais complexo do que um código não-genérico e reflexivo.

Então, considere com cuidado a possibilidade de não utilizar coisas desse tipo.

Resolvido !!!

valew pela ajuda.

[quote=ViniGodoy]Esse é um dos motivos que me faz ter saudades das templates do C++…

A solução com newInstance() pode até funcionar, mas também deve disparar alguns “warnings” na sua cabeça.
Veja os problemas:

  1. O código assume que existe um construtor padrão, e que ele é suficiente;
  2. Se isso mudar, o código não dará erro de compilação, só de execução;
  3. É certamente mais complexo do que um código não-genérico e reflexivo.

Então, considere com cuidado a possibilidade de não utilizar coisas desse tipo.[/quote]

Na realidade isso é um tipo de inversão de dependencia e não de genericos. A ideia é plugar a implementação
da classe através da instanciação dela dentro da classe que a contém. É o mesmo principio de E e = new E() que o tingol falou e que se usa muito ainda.
Só que se pensa “se eu passar um classe generica eu posso instancia-la genericamente” quando deveria pensar “eu quero injetar uma implementação de E” Para isso eu tenho que promover a injeção dessa instancia ou usar um ServiceLocator da vida. É ignorar DI que é errado e não newInstance() ou generics :wink:

Ou seja, meu exemplo seria melhor assim:

PlanoSaude<Funcionario> = new PlanoSaude<Funcionario> (new Diretor());

Ou seja, a classe PlanoSaude não deve criar ela mesma os funcionários ou diretores; ela deve receber instâncias dessas classes.

Sim, vc está certo.

Só ressaltei pq se o java suportasse uma construção como:
E e = new E();

Poderia fazer verificações em tempo de compilação, e testar se E realmente tem um construtor sem qualquer tipo de parâmetros. Coisa que o C# e o C++ fazem muito bem.

No caso da instanciação com reflection isso não ocorre… se vc fizer caca, o erro vai cair só durante a execução.

Depois que o Neal Gafter saiu da Sun (e ele deixou de ser vidraça para ser estilingue :stuck_out_tongue: ) , ele sugeriu que essa parte de Generics também aceitasse “reification”, ou seja, que o tipo E também estivesse disponível para a classe poder fazer algo como “E e = new E()” e outras coisas.

[quote=thingol]Depois que o Neal Gafter saiu da Sun (e ele deixou de ser vidraça para ser estilingue :stuck_out_tongue: ) , ele sugeriu que essa parte de Generics também aceitasse “reification”, ou seja, que o tipo E também estivesse disponível para a classe poder fazer algo como “E e = new E()” e outras coisas.
[/quote]

Isso é o tipo de gambiarra que o C faz e que fere o conceito OO profundamente.
Se E é uma interface como fica toda esta historia ? O new tem que saber que está chamando uma interface ?
Imaginem

PlanoSaude<Funcionario> = new PlanoSaude<Funcionario> (); //(1)

com Funcionario sendo interface e


class PlanoSaude<E> {

        E oCara;
         PlanoSaude(){
                oCara =  new E();// (2)
        }

}

Como a linha 1 sabe do erro da linha 2 ?

É por essas e por outras que erasure é suficiente. Porque dar poder de mais é tornar Java em C++. Ou seja, na linguagem mais baseada em gambiarra que existe.

O C não faz, quem faz é o C++.

Na verdade, não é uma gambiarra. Pq o conceito de templates não foi feito com a intenção de ser compatível com OO. É um paradigma totalmente diferente, chamado Metaprogramação e que, realmente, em muitos casos é contraditório à OO. A comunidade C++ está ciente disso, como você pode ver neste artigo aqui). Essa, na verdade, é a grande característica que difere o C++ de outras linguagens (inclusive o C): a possibilidade de programação multi-paradigma. Além da metaprogramação, o C++ ainda inclui o paradigma estruturado, muito baseado no C.

Se você ver a programação genérica do C++ vai ver que ela tenta expandir as possibilidades de reuso, estendendo a linguagem C++ e praticamente eliminando a necessidade de tipagem. É justamente o oposto do conceito de generics, que torna a tipagem mais forte e permite que uma classe que, de outra forma seria aberta demais (como a antiga List) fique mais restrita (List ou List<? extends Classe> ).

Tipagem forte é um dos pontos chaves da Orientação a Objetos: na OO, vc define classes, que nada mais são do que tipos fortes e essas classes devem interagir com um grupo restrito de outras classes, também de tipo forte. E o Java é uma linguagem que se orgulha de implementar com grande perfeição o conceito de OO. Por isso, ao meu ver, a implementação dos generics reforçando o conceito de tipos (e não como no C++) foi acertada. Mesmo que a solução final não seja tão poderosa.

Mas lógico… a interação entre dois paradigmas não é suave. O que é bom num lugar, pode ser radicalmente negativo em outro. E, embora você possa realmente aproveitar os pontos fortes de cada paradigma em diversas situações no C++, vai ter aquelas em que você terá que encarar filosofias inconsistentes. E estou falando de maneiras totalmente diferentes de pensar no problema, não só de mecanismos de programação.

Será que adicionar tanta complexidade vale a pena? Já vi muitas coisas interessantíssimas que são possíveis com a metaprogramação, que nem sequer passam nos sonhos dos programadores java… mas entre essas coisas, encontram-se erros obscuros também…

O compilador teria a capacidade de saber no exato momento que você tentasse fazer:

Classe<Interface> x = new Classe<Interface>();

O compilador então acharia dentro do código de classe algo como:

Interface e = new Interface();  //Antes E e = new E();

E geraria um erro de compilação.

O compilador teria a capacidade de saber no exato momento que você tentasse fazer:

Classe<Interface> x = new Classe<Interface>();

O compilador então acharia dentro do código de classe algo como:

Interface e = new Interface();  //Antes E e = new E();

E geraria um erro de compilação.[/quote]

Sim, no C++ onde ha substuição sim (é gerado um novo codigo com E subtituido)
Eu estava falando em java em que não ha substituição/geração de codigo.

Pior, a classe pode ser abstrata e o uso de interface poderia ser feito noutra classe que nem sequer está no projeto. E aí ?

O compilador teria a capacidade de saber no exato momento que você tentasse fazer:

Classe<Interface> x = new Classe<Interface>();

O compilador então acharia dentro do código de classe algo como:

Interface e = new Interface();  //Antes E e = new E();

E geraria um erro de compilação.[/quote]

Sim, no C++ onde ha substuição sim (é gerado um novo codigo com E subtituido)
Eu estava falando em java em que não ha substituição/geração de codigo.

Pior, a classe pode ser abstrata e o uso de interface poderia ser feito noutra classe que nem sequer está no projeto. E aí ? [/quote]

Bastaria na assinatura da classe parametrizada dizer que o tipo E tem de ser concreto. Adicionando recursos na linguagem, TODOS os problemas que voces citaram, no caso de poder dar new em E, somem, porem aparecem problemas de compatibilidade se voce for permitir o uso dessas classes sem generics.

[quote=ViniGodoy]
Será que adicionar tanta complexidade vale a pena? Já vi muitas coisas interessantíssimas que são possíveis com a metaprogramação, que nem sequer passam nos sonhos dos programadores java… mas entre essas coisas, encontram-se erros obscuros também…[/quote]

Cara, pode citar um exemplo?
Algo que passe dos nossos sonhos o.0
Por acaso ele não pensa sózinho, pensa? ^^

O fato de não haver substituição no resultado final não implica em dizer que o compilador não faça, ou não saiba como ficaria a classe durante a compilação. Aliás, ele sabe muito bem, tanto que valida os seus sets. O compilador gera bastante código também, em especial, faz os casts automaticamente. Os casts aparecem num bytecode descompilado, por exemplo.

Você diz a classe que será substituída em T? Nesse caso, não poderia haver new, concorda? Como dar new numa classe abstrata?

Se ela só “vem de fora”, não haverá new T(). E daí o código compila.

Mas vc tem razão. Com type erasure, é impossível implementar new T.

[quote=Mark_Ameba]Cara, pode citar um exemplo?
Algo que passe dos nossos sonhos o.0
Por acaso ele não pensa sózinho, pensa? ^^[/quote]

Não, ainda não pensa sozinho. Mas que tal essa biblioteca gráfica matemática que deixa vc construir gráficos assim:

Plotdata x(-3.0, 3.0), y = sin(x) - 0.5*x;
plot(x, y);

Essa notação é mais próxima da matemática, concorda?

Essa ainda foi fácil. Ou que tal uma função que transforme um número binário em decimal em tempo de compilação?

int x = binary<1101011>;

Existem APIs para processamento de XML, como a rapidxml, que usa a meta-programação para atingir uma performance absurda.

Na minha API, tenho classes que lidam com vetores matemáticos. Elas aceitam qualquer coisa que tenha o operador [] sobrecarregado para oferecer 3 índices, com esses 3 valores. Isso inclui, arrays primitivos e outras classes. Isso garante que haja integração com outras APIs, com alto grau de segurança, sem a necessidade de casts e sem a necessidade de eu conhecer essas APIs ou declarar uma interface.

Na verdade, não passam pelos sonhos dos programadores java não pq eles seriam menos capazes. Por favor, eu não quis ser pejorativo.
Mas sim, pq a linguagem simplesmente não dá mecanismos para que essas coisas sejam sequer possíveis.

Então, os sonhos deles se concentram em outros lugares. :slight_smile:
Aliás, a reflexão também faz coisas que não passa pela cabeça dos programadores C++ também. :wink:
No mundo C++ existe o RTTI, que é limitadíssimo e muito lento.