it-swarm-pt.tech

O que é legal nos genéricos, por que usá-los?

Pensei em oferecer esse softball a quem quisesse jogá-lo para fora do parque. O que são genéricos, quais são as vantagens dos genéricos, por que, onde, como devo usá-los? Por favor, mantenha-o bastante básico. Obrigado.

80
MrBoJangles
  • Permite que você escreva códigos/use métodos de biblioteca que sejam seguros para o tipo, ou seja, uma Lista <string> é garantida como uma lista de strings.
  • Como o uso de genéricos, o compilador pode executar verificações em tempo de compilação do código para segurança de tipo, ou seja, você está tentando inserir um int nessa lista de cadeias? Usar um ArrayList causaria um erro de tempo de execução menos transparente.
  • Mais rápido do que usar objetos, pois evita boxe/unboxing (onde .net precisa converter tipos de valor para tipos de referência ou vice-versa ) ou converter objetos para o tipo de referência necessário.
  • Permite escrever código aplicável a muitos tipos com o mesmo comportamento subjacente, ou seja, um Dictionary <string, int> usa o mesmo código subjacente que um Dictionary <DateTime, double>; usando genéricos, a equipe de estrutura precisou escrever apenas um trecho de código para alcançar os dois resultados com as vantagens mencionadas acima.
120
ljs

Não é necessário digitar uma das maiores vantagens de Java genéricos , pois ele executará a verificação de tipo na compilação- Isso reduzirá a possibilidade de ClassCastException s que podem ser lançados em tempo de execução e pode levar a um código mais robusto.

Mas suspeito que você esteja plenamente ciente disso.

Toda vez que olho para Generics, sinto uma dor de cabeça. Acho que a melhor parte de Java é a simplicidade, a sintaxe mínima e os genéricos não são simples) e adicionam uma quantidade significativa de nova sintaxe.

No começo, também não vi o benefício dos genéricos. Comecei a aprender Java a partir da sintaxe 1.4 (apesar de Java 5 estava esgotado no momento)) e quando encontrei genéricos, senti que havia mais código para escrever e eu realmente não entendi os benefícios.

Os IDEs modernos facilitam a escrita de códigos com genéricos.

A maioria dos IDEs modernos e decentes é inteligente o suficiente para ajudar na escrita de códigos com genéricos, especialmente na conclusão de códigos.

Aqui está um exemplo de como criar um Map<String, Integer> com um HashMap. O código que eu precisaria digitar é:

Map<String, Integer> m = new HashMap<String, Integer>();

E, de fato, é muito para digitar apenas para criar um novo HashMap. No entanto, na realidade, eu só precisava digitar isso muito antes que o Eclipse soubesse o que eu precisava:

Map<String, Integer> m = new Ha Ctrl+Space

É verdade que eu precisava selecionar HashMap em uma lista de candidatos, mas basicamente o IDE sabia o que adicionar, incluindo os tipos genéricos. Com as ferramentas certas, o uso de genéricos isn muito ruim.

Além disso, como os tipos são conhecidos, ao recuperar elementos da coleção genérica, o IDE atuará como se esse objeto já fosse um objeto de seu tipo declarado - não há necessidade de converter para que o IDE saiba qual é o tipo do objeto.

Uma das principais vantagens dos genéricos vem do modo como ele funciona bem com os novos recursos Java 5 recursos. Aqui está um exemplo de lançamento números inteiros em um Set e calculando seu total:

Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(42);

int total = 0;
for (int i : set) {
  total += i;
}

Nesse pedaço de código, há três novos recursos Java 5 presentes:

Primeiro, genéricos e autoboxing de primitivos permitem as seguintes linhas:

set.add(10);
set.add(42);

O inteiro 10 é autoboxed em um Integer com o valor de 10. (E o mesmo para 42). Então esse Integer é lançado no Set que é conhecido por conter Integer s. Tentar lançar um String causaria um erro de compilação.

A seguir, o loop for-each leva todos os três:

for (int i : set) {
  total += i;
}

Primeiro, os Set que contêm Integer s são usados ​​em um loop para cada. Cada elemento é declarado como int e isso é permitido, pois Integer é retirado da caixa de seleção para a primitiva int. E o fato de que esse unboxing ocorre é conhecido porque os genéricos foram usados ​​para especificar que havia Integer s retidos no Set.

Os genéricos podem ser a cola que reúne os novos recursos introduzidos em Java 5, e torna a codificação mais simples e segura. E na maioria das vezes os IDEs são inteligentes o suficiente para ajudá-lo com boas sugestões, geralmente, não será muito mais digitação.

E, francamente, como pode ser visto no exemplo Set, acho que a utilização dos recursos Java 5) pode tornar o código mais conciso e robusto.

Editar - um exemplo sem genéricos

A seguir, é apresentada uma ilustração do exemplo Set acima, sem o uso de genéricos. É possível, mas não é exatamente agradável:

Set set = new HashSet();
set.add(10);
set.add(42);

int total = 0;
for (Object o : set) {
  total += (Integer)o;
}

(Observação: o código acima gera um aviso de conversão não verificado em tempo de compilação.)

Ao usar coleções não genéricas, os tipos inseridos na coleção são objetos do tipo Object. Portanto, neste exemplo, um Object é o que está sendo add ed no conjunto.

set.add(10);
set.add(42);

Nas linhas acima, o autoboxing está em jogo - o valor primitivo int10 e 42 estão sendo autoboxed em objetos Integer, que estão sendo adicionados ao Set. No entanto, lembre-se de que os objetos Integer estão sendo manipulados como Object s, pois não há informações de tipo para ajudar o compilador a saber que tipo o Set deve esperar.

for (Object o : set) {

Esta é a parte que é crucial. A razão pela qual cada loop funciona é porque o Set implementa a interface Iterable , que retorna um Iterator com informações de tipo, se houver. (Iterator<T>, isso é.)

No entanto, como não há informações de tipo, o Set retornará um Iterator que retornará os valores em Set como Object s, e isso é por que o elemento que está sendo recuperado no loop for-each deve deve ser do tipo Object.

Agora que o Object é recuperado do Set, ele precisa ser convertido para um Integer manualmente para executar a adição:

  total += (Integer)o;

Aqui, um typecast é realizado de um Object para um Integer. Nesse caso, sabemos que isso sempre funcionará, mas a conversão manual de caracteres sempre me faz sentir que é um código frágil que pode ser danificado se uma pequena alteração for feita em outro local. (Acho que todo tipo de anúncio está esperando um ClassCastException, mas discordo ...)

O Integer agora está unboxed em um int e é permitido executar a adição na variável inttotal.

Espero poder ilustrar que os novos recursos do Java 5 são possíveis de usar com código não genérico, mas não são tão limpos e diretos quanto escrever código com genéricos. , na minha opinião, para tirar o máximo proveito dos novos recursos do Java 5, deve-se procurar por genéricos, se pelo menos, permitir verificações em tempo de compilação para evitar que lançar exceções em tempo de execução.

20
coobird

Se você pesquisasse o banco de dados de erros Java pouco antes do lançamento do 1.5, você encontrará sete vezes mais erros com NullPointerException do que ClassCastException. parece que é um ótimo recurso encontrar bugs, ou pelo menos bugs que persistem após um pequeno teste de fumaça.

Para mim, a enorme vantagem dos genéricos é que eles documentam no código informações importantes do tipo. Se não quisesse que essas informações de tipo fossem documentadas no código, usaria uma linguagem de tipo dinâmico ou pelo menos uma linguagem com inferência de tipo mais implícita.

Manter as coleções de um objeto para si não é um estilo ruim (mas o estilo comum é efetivamente ignorar o encapsulamento). Depende bastante do que você está fazendo. Passar coleções para "algoritmos" é um pouco mais fácil de verificar (no momento ou antes do tempo de compilação) com genéricos.

15
Tom Hawtin - tackline

Os genéricos em Java facilitam polimorfismo paramétrico . Por meio de parâmetros de tipo, você pode passar argumentos para tipos. Assim como um método como String foo(String s) modela alguns comportamento, não apenas para uma sequência específica, mas para qualquer sequência s, portanto, um tipo como List<T> modela algum comportamento, não apenas para um tipo específico, mas para qualquer tipo. List<T> diz que para qualquer tipo T, existe um tipo de List cujos elementos são Ts. Então List é realmente um tipo construtor. Ele pega um tipo como argumento e cria outro tipo como resultado.

Aqui estão alguns exemplos de tipos genéricos que eu uso todos os dias. Primeiro, uma interface genérica muito útil:

public interface F<A, B> {
  public B f(A a);
}

Essa interface diz que para alguns tipos, A e B, existe uma função (chamada f) que pega um A e retorna a B. Quando você implementa essa interface, A e B podem ser de qualquer tipo, desde que você forneça uma função f que pega o primeiro e retorna o último. Aqui está um exemplo de implementação da interface:

F<Integer, String> intToString = new F<Integer, String>() {
  public String f(int i) {
    return String.valueOf(i);
  }
}

Antes dos genéricos, o polimorfismo era alcançado por subclassing usando a palavra-chave extends. Com os genéricos, podemos realmente eliminar a subclasse e usar o polimorfismo paramétrico. Por exemplo, considere uma classe parametrizada (genérica) usada para calcular códigos de hash para qualquer tipo. Em vez de substituir Object.hashCode (), usaríamos uma classe genérica como esta:

public final class Hash<A> {
  private final F<A, Integer> hashFunction;

  public Hash(final F<A, Integer> f) {
    this.hashFunction = f;
  }

  public int hash(A a) {
    return hashFunction.f(a);
  }
}

Isso é muito mais flexível do que usar herança, porque podemos continuar com o tema de usar composição e polimorfismo paramétrico sem bloquear hierarquias frágeis.

Os genéricos de Java não são perfeitos. Você pode abstrair sobre tipos, mas não pode abstrair sobre construtores de tipos, por exemplo. Ou seja, você pode dizer "para qualquer tipo T", mas não pode dizer "para qualquer tipo T que usa um parâmetro de tipo A".

Eu escrevi um artigo sobre esses limites de Java genéricos, aqui.

Uma grande vitória dos genéricos é que eles permitem evitar subclasses. A subclassificação tende a resultar em hierarquias de classe frágeis que são difíceis de estender e classes que são difíceis de entender individualmente sem olhar para toda a hierarquia.

Antes dos genéricos, você pode ter classes como Widget estendidas por FooWidget, BarWidget e BazWidget, com os genéricos você pode ter uma única classe genérica Widget<A> que utiliza um Foo, Bar ou Baz em seu construtor para fornecer Widget<Foo>, Widget<Bar> e Widget<Baz>.

10
Apocalisp

Os genéricos evitam o impacto no desempenho do boxe e do unboxing. Basicamente, veja ArrayList vs List <T>. Ambos fazem as mesmas coisas principais, mas a Lista <T> será muito mais rápida, porque você não precisa encaixar o objeto de/para a caixa.

8
Darren Kopp
  • Coleções digitadas - mesmo se você não quiser usá-las, provavelmente precisará lidar com elas de outras bibliotecas e outras fontes.

  • Digitação genérica na criação de classe:

    classe pública Foo <T> {public T get () ...

  • Evitar vazamentos - eu sempre não gostei de coisas como

    new Comparator {public int compareTo (Objeto o) {if (o exemplo de classIcareAbout) ...

Onde você está essencialmente procurando uma condição que só deveria existir porque a interface é expressa em termos de objetos.

Minha reação inicial aos genéricos foi semelhante à sua - "muito bagunçada, muito complicada". Minha experiência é que, depois de usá-los um pouco, você se acostuma a eles, e o código sem eles parece menos claro e menos confortável. Além disso, o resto do mundo Java os usa para que você tenha que entrar com o programa eventualmente, certo?

5
Steve B.

Para dar um bom exemplo. Imagine que você tem uma classe chamada Foo

public class Foo
{
   public string Bar() { return "Bar"; }
}

Exemplo 1 Agora você deseja ter uma coleção de objetos Foo. Você tem duas opções, LIst ou ArrayList, que funcionam de maneira semelhante.

Arraylist al = new ArrayList();
List<Foo> fl = new List<Foo>();

//code to add Foos
al.Add(new Foo());
f1.Add(new Foo());

No código acima, se eu tentar adicionar uma classe de FireTruck em vez de Foo, o ArrayList a adicionará, mas a Lista Genérica de Foo fará com que uma exceção seja lançada.

Exemplo dois.

Agora você tem suas duas listas de matrizes e deseja chamar a função Bar () em cada uma. Como o hte ArrayList é preenchido com objetos, você deve convertê-los antes de poder chamar a barra. Mas como a Lista Genérica de Foo pode conter apenas Foos, você pode chamar Bar () diretamente sobre eles.

foreach(object o in al)
{
    Foo f = (Foo)o;
    f.Bar();
}

foreach(Foo f in fl)
{
   f.Bar();
}
5
Peter Lange

Eu gosto deles porque eles oferecem uma maneira rápida de definir um tipo personalizado (como eu os uso de qualquer maneira).

Por exemplo, em vez de definir uma estrutura que consiste em uma sequência de caracteres e um número inteiro, e depois ter que implementar um conjunto inteiro de objetos e métodos sobre como acessar uma matriz dessas estruturas e assim por diante, você pode simplesmente criar um Dicionário

Dictionary<int, string> dictionary = new Dictionary<int, string>();

E o compilador/IDE faz o resto do trabalho pesado. Um dicionário em particular permite que você use o primeiro tipo como chave (sem valores repetidos).

5
Tom Kidd

O melhor benefício para os genéricos é a reutilização de código. Digamos que você tenha muitos objetos de negócios e escreverá um código MUITO semelhante para cada entidade executar as mesmas ações. (I.E operações Linq to SQL).

Com os genéricos, você pode criar uma classe que poderá operar, dado qualquer um dos tipos herdados de uma determinada classe base ou implementar uma determinada interface, como:

public interface IEntity
{

}

public class Employee : IEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int EmployeeID { get; set; }
}

public class Company : IEntity
{
    public string Name { get; set; }
    public string TaxID { get; set }
}

public class DataService<ENTITY, DATACONTEXT>
    where ENTITY : class, IEntity, new()
    where DATACONTEXT : DataContext, new()
{

    public void Create(List<ENTITY> entities)
    {
        using (DATACONTEXT db = new DATACONTEXT())
        {
            Table<ENTITY> table = db.GetTable<ENTITY>();

            foreach (ENTITY entity in entities)
                table.InsertOnSubmit (entity);

            db.SubmitChanges();
        }
    }
}

public class MyTest
{
    public void DoSomething()
    {
        var dataService = new DataService<Employee, MyDataContext>();
        dataService.Create(new Employee { FirstName = "Bob", LastName = "Smith", EmployeeID = 5 });
        var otherDataService = new DataService<Company, MyDataContext>();
            otherDataService.Create(new Company { Name = "ACME", TaxID = "123-111-2233" });

    }
}

Observe a reutilização do mesmo serviço, considerando os diferentes tipos no método DoSomething acima. Verdadeiramente elegante!

Há muitas outras ótimas razões para usar genéricos no seu trabalho, esse é o meu favorito.

5
Dean Poulin

Você nunca escreveu um método (ou uma classe) em que o conceito-chave do método/classe não estava fortemente vinculado a um tipo de dados específico das variáveis ​​de parâmetros/instância (pense em lista vinculada, funções max/min, pesquisa binária etc.).

Você nunca desejou poder reutilizar o código/algorthm sem recorrer à reutilização cut-n-paste ou comprometer a digitação forte (por exemplo, eu quero um List de Strings, não um List de coisas que eu espero são strings!)?

É por isso que você deve querer usar genéricos (ou algo melhor).

4
Bert F

Não se esqueça que os genéricos não são usados ​​apenas por classes, eles também podem ser usados ​​por métodos. Por exemplo, pegue o seguinte trecho:

private <T extends Throwable> T logAndReturn(T t) {
    logThrowable(t); // some logging method that takes a Throwable
    return t;
}

É simples, mas pode ser usado com muita elegância. O bom é que o método retorna o que foi dado. Isso ajuda quando você está lidando com exceções que precisam ser novamente reproduzidas para o chamador:

    ...
} catch (MyException e) {
    throw logAndReturn(e);
}

O ponto é que você não perde o tipo passando-o por um método. Você pode lançar o tipo correto de exceção, em vez de apenas um Throwable, que seria tudo o que você poderia fazer sem os genéricos.

Este é apenas um exemplo simples de um uso para métodos genéricos. Existem várias outras coisas legais que você pode fazer com métodos genéricos. O mais legal, na minha opinião, é o tipo de inferir com genéricos. Veja o exemplo a seguir (extraído da 2ª edição de Josh Bloch, Effective Java]:

...
Map<String, Integer> myMap = createHashMap();
...
public <K, V> Map<K, V> createHashMap() {
    return new HashMap<K, V>();
}

Isso não faz muito, mas reduz um pouco a confusão quando os tipos genéricos são longos (ou aninhados; ou seja, Map<String, List<String>>).

3
jigawot

Na documentação do Sun Java, em resposta a "por que devo usar genéricos?":

"Os genéricos fornecem uma maneira de você comunicar o tipo de uma coleção ao compilador, para que possa ser verificado. Depois que o compilador conhece o tipo de elemento da coleção, o compilador pode verificar se você usou a coleção de forma consistente e pode inserir a conversão correta dos valores que estão sendo retirados da coleção ... O código usando genéricos é mais claro e seguro .... o compilador pode verificar no tempo de compilação que as restrições de tipo não são violadas no tempo de execução [ênfase minha] Como o programa é compilado sem avisos, podemos afirmar com certeza que ele não lançará uma ClassCastException em tempo de execução. O efeito líquido do uso de genéricos, especialmente em programas grandes, é melhor legibilidade e robustez. [ênfase minha] "

2
Demi

a jvm lança de qualquer maneira ... cria implicitamente o código que trata o tipo genérico como "Objeto" e cria a conversão para a instanciação desejada. Java genéricos são apenas açúcar sintático.

2
Anonymous Coward

A principal vantagem, como aponta Mitchel, é a digitação forte, sem a necessidade de definir várias classes.

Dessa forma, você pode fazer coisas como:

List<SomeCustomClass> blah = new List<SomeCustomClass>();
blah[0].SomeCustomFunction();

Sem genéricos, você teria que usar blá [0] no tipo correto para acessar suas funções.

2
Kevin Pang

Eu sei que essa é uma pergunta em C #, mas genéricos também são usados ​​em outros idiomas, e seus objetivos/uso são bastante semelhantes.

As coleções Java usam genéricos desde Java 1.5. Portanto, um bom lugar para usá-las é quando você está criando seu próprio objeto semelhante a uma coleção.

Um exemplo que vejo em quase toda parte é uma classe Pair, que contém dois objetos, mas precisa lidar com esses objetos de maneira genérica.

class Pair<F, S> {
    public final F first;
    public final S second;

    public Pair(F f, S s)
    { 
        first = f;
        second = s;   
    }
}  

Sempre que você usa essa classe Pair, pode especificar com que tipo de objetos deseja lidar e quaisquer problemas de conversão de tipos aparecerão no tempo de compilação, em vez do tempo de execução.

Os genéricos também podem ter seus limites definidos com as palavras-chave 'super' e 'extends'. Por exemplo, se você deseja lidar com um tipo genérico, mas deseja garantir que ela estenda uma classe chamada Foo (que possui um método setTitle):

public class FooManager <F extends Foo>{
    public void setTitle(F foo, String title) {
        foo.setTitle(title);
    }
}

Embora não seja muito interessante por si só, é útil saber que sempre que você lida com um FooManager, sabe que ele manipulará os tipos MyClass e que MyClass estende o Foo.

2
etchasketch

Eu os uso, por exemplo, em um GenericDao implementado com SpringORM e Hibernate que se parece com isso

public abstract class GenericDaoHibernateImpl<T> 
    extends HibernateDaoSupport {

    private Class<T> type;

    public GenericDaoHibernateImpl(Class<T> clazz) {
        type = clazz;
    }

    public void update(T object) {
        getHibernateTemplate().update(object);
    }

    @SuppressWarnings("unchecked")
    public Integer count() {
    return ((Integer) getHibernateTemplate().execute(
        new HibernateCallback() {
            public Object doInHibernate(Session session) {
                    // Code in Hibernate for getting the count
                }
        }));
    }
  .
  .
  .
}

Ao usar genéricos, minhas implementações deste DAOs forçam o desenvolvedor a passar apenas as entidades para as quais foram projetadas, apenas subclassificando o GenericDao

public class UserDaoHibernateImpl extends GenericDaoHibernateImpl<User> {
    public UserDaoHibernateImpl() {
        super(User.class);     // This is for giving Hibernate a .class
                               // work with, as generics disappear at runtime
    }

    // Entity specific methods here
}

Minha pequena estrutura é mais robusta (tem coisas como filtragem, carregamento lento, pesquisa). Apenas simplifiquei aqui para dar um exemplo

Eu, como Steve e você, disse no início "Muito bagunçado e complicado" mas agora vejo suas vantagens

1
victor hugo

Os genéricos permitem criar objetos que são fortemente digitados, mas você não precisa definir o tipo específico. Eu acho que o melhor exemplo útil é a lista e classes semelhantes.

Usando a lista genérica, você pode ter uma Lista de Lista da Lista o que quiser e sempre pode fazer referência à digitação forte, não precisa converter ou algo parecido com uma Matriz ou Lista padrão.

1
Mitchel Sellers

Os genéricos permitem que você use digitação forte para objetos e estruturas de dados que devem poder conter qualquer objeto. Ele também elimina previsões tediosas e caras ao recuperar objetos de estruturas genéricas (boxe/unboxing).

Um exemplo que usa ambos é uma lista vinculada. Qual seria a utilidade de uma classe de lista vinculada se pudesse usar apenas o objeto Foo? Para implementar uma lista vinculada que pode manipular qualquer tipo de objeto, a lista vinculada e os nós em uma classe interna de nó hipotético devem ser genéricos se você desejar que a lista contenha apenas um tipo de objeto.

1
Steve Landey

Benefícios óbvios como "segurança de tipo" e "sem vazamento" já foram mencionados, então talvez eu possa falar sobre outros "benefícios" que espero que ajude.

Antes de tudo, genéricos é um conceito independente da linguagem e, na IMO, pode fazer mais sentido se você pensar em polimorfismos regulares (em tempo de execução) ao mesmo tempo.

Por exemplo, o polimorfismo que conhecemos do design orientado a objetos tem uma noção de tempo de execução, na qual o objeto chamador é descoberto em tempo de execução à medida que a execução do programa ocorre e o método relevante é chamado de acordo, dependendo do tipo de tempo de execução. Em genéricos, a ideia é um pouco semelhante, mas tudo acontece em tempo de compilação. O que isso significa e como você o utiliza?

(Vamos continuar com métodos genéricos para mantê-lo compacto) Isso significa que você ainda pode ter o mesmo método em classes separadas (como anteriormente em classes polimórficas), mas desta vez elas são geradas automaticamente pelo compilador, dependendo dos tipos definidos em tempo de compilação. Você parametriza seus métodos no tipo fornecido em tempo de compilação. Portanto, em vez de escrever os métodos a partir do zero para cada tipo que você possui no polimorfismo de tempo de execução (substituição de método), permite que os compiladores façam o trabalho durante a compilação. Isso tem uma vantagem óbvia, pois você não precisa inferir todos os tipos possíveis que podem ser usados ​​no seu sistema, o que o torna muito mais escalável sem uma alteração no código.

As aulas funcionam da mesma maneira. Você parametriza o tipo e o código é gerado pelo compilador.

Depois de ter a idéia de "tempo de compilação", você pode usar tipos "limitados" e restringir o que pode ser passado como um tipo parametrizado por meio de classes/métodos. Portanto, você pode controlar o que deve ser passado, o que é uma coisa poderosa, especialmente se você tiver uma estrutura consumida por outras pessoas.

public interface Foo<T extends MyObject> extends Hoo<T>{
    ...
}

Ninguém pode definir sth diferente de MyObject agora.

Além disso, você pode "impor" restrições de tipo nos argumentos do método, o que significa que você pode garantir que ambos os argumentos do método dependam do mesmo tipo.

public <T extends MyObject> foo(T t1, T t2){
    ...
}   

Espero que tudo isso faça sentido.

1
stdout

Outra vantagem do uso de genéricos (especialmente com coleções/listas) é a verificação do tipo de tempo de compilação. Isso é realmente útil ao usar uma lista genérica em vez de uma lista de objetos.

1
Chris Pietschmann

Se sua coleção contiver tipos de valor, eles não precisarão encaixar/desmarcar objetos quando inseridos na coleção, para que seu desempenho aumente drasticamente. Complementos interessantes, como o compartilhador, podem gerar mais código para você, como os loops foreach.

1
gt124

O motivo mais único é que eles fornecem Segurança de tipo

List<Customer> custCollection = new List<Customer>;

ao contrário de,

object[] custCollection = new object[] { cust1, cust2 };

como um exemplo simples.

1
Vin

Em resumo, os genéricos permitem especificar com mais precisão o que você pretende fazer (digitação mais forte).

Isso tem vários benefícios para você:

  • Como o compilador sabe mais sobre o que você deseja fazer, ele permite que você omita muita conversão de tipo, porque já sabe que o tipo será compatível.

  • Isso também fornece feedback anterior sobre as correções do seu programa. Coisas que anteriormente falhariam no tempo de execução (por exemplo, porque um objeto não pôde ser convertido no tipo desejado) agora falham no tempo de compilação e você pode corrigir o erro antes que o departamento de teste arquive um relatório de erro criptográfico.

  • O compilador pode fazer mais otimizações, como evitar boxe, etc.

1
Thomas Danecker

Algumas coisas para adicionar/expandir (falando do ponto de vista do .NET):

Tipos genéricos permitem criar classes e interfaces baseadas em função. Isso já foi dito em termos mais básicos, mas acho que você começa a projetar seu código com classes implementadas de maneira independente de tipo - o que resulta em código altamente reutilizável.

Argumentos genéricos sobre métodos podem fazer a mesma coisa, mas também ajudam a aplicar o princípio "Tell Don't Ask" à transmissão, ou seja, "me dê o que eu quero e, se você não puder, me diga o porquê".

1
SpongeJim

O uso de genéricos para coleções é simplesmente simples e limpo. Mesmo se você fizer isso em qualquer outro lugar, o ganho das coleções é uma vitória para mim.

List<Stuff> stuffList = getStuff();
for(Stuff stuff : stuffList) {
    stuff.do();
}

vs

List stuffList = getStuff();
Iterator i = stuffList.iterator();
while(i.hasNext()) {
    Stuff stuff = (Stuff)i.next();
    stuff.do();
}

ou

List stuffList = getStuff();
for(int i = 0; i < stuffList.size(); i++) {
    Stuff stuff = (Stuff)stuffList.get(i);
    stuff.do();
}

Só isso vale o "custo" marginal dos genéricos, e você não precisa ser um guru genérico para usar isso e obter valor.

0
Will Hartung

Os genéricos também oferecem a capacidade de criar objetos/métodos mais reutilizáveis ​​e, ao mesmo tempo, fornecer suporte específico ao tipo. Você também ganha muito desempenho em alguns casos. Não conheço a especificação completa dos genéricos Java, mas no .NET posso especificar restrições no parâmetro Type, como Implementa uma interface, Construtor e Derivação).

0
Eric Schneider

Certa vez, dei uma palestra sobre esse tópico. Você pode encontrar meus slides, código e gravação de áudio em http://www.adventuresinsoftware.com/generics/ .

0
Michael L Perry