Recentemente, vi uma descrição muito boa da estrutura de coleção em um livro J2EE. Filtrei-a e publiquei-a para compartilhar com todos. A estrutura de coleção fornece interfaces e classes para gerenciar coleções de objetos. a seguir está a descrição de cada componente.
Interface de coleção
Coleção é a interface de coleção mais básica. Uma Coleção representa um conjunto de Objetos, ou seja, os elementos da Coleção. Algumas Coleções permitem elementos idênticos e outras não. Alguns tipos e outros não. O Java SDK não fornece classes que herdam diretamente da Collection. As classes fornecidas pelo Java SDK são todas "subinterfaces" que herdam da Collection, como List e Set.
Todas as classes que implementam a interface Collection devem fornecer dois construtores padrão: um construtor sem parâmetros para criar uma Coleção vazia e um construtor de parâmetro Collection para criar uma nova Coleção. A Coleção de entrada possui os mesmos elementos. O último construtor permite ao usuário copiar uma coleção.
Como iterar cada elemento da coleção? Independentemente do tipo real de Coleção, ele suporta um método iterator(), que retorna um iterador que pode ser usado para acessar cada elemento da Coleção, um por um. O uso típico é o seguinte:
Copie o código do código da seguinte forma:
Iterator it = Collection.iterator(); // Obtenha um iterador
enquanto(it.hasNext()) {
Object obj = it.next(); // Obtém o próximo elemento
}
As duas interfaces derivadas da interface Collection são List e Set.
Interface de lista Lista é uma coleção ordenada. Usando esta interface, você pode controlar com precisão a posição de inserção de cada elemento. Os usuários podem acessar os elementos da Lista usando o índice (a posição do elemento na Lista, semelhante a um subscrito de array), que é semelhante a um array Java.
Ao contrário do Set mencionado abaixo, List permite os mesmos elementos.
Além do método iterator() necessário para a interface Collection, List também fornece um método listIterator(), que retorna uma interface ListIterator Comparado com a interface Iterator padrão, ListIterator possui mais alguns métodos add() e outros métodos, permitindo adições. Exclua, defina elementos e avance ou retroceda.
As classes comuns que implementam a interface List são LinkedList, ArrayList, Vector e Stack.
Classe LinkedList LinkedList implementa a interface List e permite elementos nulos. Além disso, o LinkedList fornece métodos adicionais de obtenção, remoção e inserção no início ou no final do LinkedList. Essas operações permitem que LinkedList seja usado como pilha, fila ou deque.
Observe que LinkedList não possui métodos sincronizados. Se vários threads acessarem uma lista ao mesmo tempo, eles próprios deverão implementar a sincronização de acesso. Uma solução alternativa é construir uma lista sincronizada ao criar a lista:
Lista lista = Collections.synchronizedList(new LinkedList(...));
Classe ArrayList ArrayList implementa arrays de tamanho variável. Permite todos os elementos, incluindo nulo. ArrayList não está sincronizado.
O tempo de execução dos métodos size, isEmpty, get e set é constante. No entanto, o custo do método add é uma constante amortizada e a adição de n elementos requer O(n) tempo. Outros métodos têm tempo de execução linear.
Cada instância de ArrayList possui uma capacidade (Capacity), que é o tamanho do array usado para armazenar elementos. Esta capacidade aumenta automaticamente à medida que novos elementos são adicionados, mas o algoritmo de crescimento não está definido. Quando um grande número de elementos precisa ser inserido, o método secureCapacity pode ser chamado para aumentar a capacidade do ArrayList antes da inserção para melhorar a eficiência da inserção.
Assim como LinkedList, ArrayList também não é sincronizado.
Classe vetorial Vector é muito semelhante a ArrayList, mas Vector é sincronizado. Embora o Iterator criado pelo Vector tenha a mesma interface do Iterator criado pelo ArrayList, porque o Vector é sincronizado, quando um Iterator é criado e está sendo usado, outra thread altera o estado do Vector (por exemplo, adicionando ou removendo algum elemento) , ConcurrentModificationException será lançada ao chamar o método Iterator, portanto, a exceção deve ser capturada.
Classe de pilha Stack herda de Vector e implementa uma pilha last-in-first-out. Stack fornece 5 métodos adicionais que permitem que Vector seja usado como uma pilha. Os métodos básicos push e pop, bem como o método peek, colocam o elemento no topo da pilha, o método vazio testa se a pilha está vazia e o método de pesquisa detecta a posição de um elemento na pilha. Stack é uma pilha vazia depois de criada.
Definir interface Set é uma coleção que não contém elementos duplicados, ou seja, quaisquer dois elementos e1 e e2 possuem e1.equals(e2)=false, e Set possui no máximo um elemento nulo.
Obviamente, o construtor Set tem uma restrição de que o parâmetro Collection passado não pode conter elementos duplicados.
Observação: objetos mutáveis devem ser manuseados com cuidado. Se um elemento mutável em um Set mudar seu estado causando Object.equals(Object)=true, isso causará alguns problemas.
Interface do mapa <BR>Por favor, note que o Mapa não herda a interface da Coleção. O Mapa fornece mapeamento de chave para valor. Um mapa não pode conter a mesma chave e cada chave só pode mapear um valor. A interface do Mapa fornece três tipos de visualizações de conjunto. O conteúdo do Mapa pode ser considerado como um conjunto de conjuntos de chaves, um conjunto de conjuntos de valores ou um conjunto de mapeamentos de valores-chave.
Classe hashtable Hashtable herda a interface Map e implementa uma tabela hash de mapeamento de valores-chave. Qualquer objeto não nulo pode ser usado como chave ou valor.
Para adicionar dados, use put(key, value) e para remover dados, use get(key). O custo de tempo dessas duas operações básicas é constante.
Hashtable ajusta o desempenho por meio de dois parâmetros: capacidade inicial e fator de carga. Normalmente, o fator de carga padrão 0,75 atinge um melhor equilíbrio entre tempo e espaço. Aumentar o fator de carga pode economizar espaço, mas o tempo de pesquisa correspondente aumentará, o que afetará operações como get e put.
Um exemplo simples de uso de Hashtable é o seguinte. Coloque 1, 2 e 3 no Hashtable e suas chaves são "um", "dois" e "três", respectivamente:
Copie o código do código da seguinte forma:
Números da tabela hash = new Hashtable();
números.put(“um”, novo Inteiro(1));
números.put(“dois”, new Integer(2));
numbers.put(“três”, new Integer(3));
Para recuperar um número, como 2, use a chave correspondente:
Inteiro n = (Inteiro)números.get(“dois”);
System.out.println(“dois = ” + n);
Como o objeto usado como chave determinará a posição do valor correspondente calculando sua função hash, qualquer objeto usado como chave deve implementar os métodos hashCode e equals. Os métodos hashCode e equals são herdados da classe raiz Object. Se você usar uma classe customizada como chave, tome muito cuidado de acordo com a definição da função hash, se os dois objetos forem iguais, ou seja, obj1.equals(. obj2)=true, então seu hashCode deve ser O mesmo, mas se dois objetos forem diferentes, seu hashCode não será necessariamente diferente. Se o hashCode de dois objetos diferentes for o mesmo, esse fenômeno é chamado de conflito. O conflito aumentará o custo de tempo de operação da tabela hash. para defini-lo bem. O método hashCode() pode acelerar as operações da tabela hash.
Se o mesmo objeto tiver hashCode diferente, a operação da tabela hash terá resultados inesperados (o método get esperado retorna nulo). Para evitar esse problema, você só precisa se lembrar de uma coisa: substituir o método equals e o método hashCode ao mesmo tempo. vez. Não escreva apenas um deles.
Hashtable é síncrono.
Classe HashMap HashMap é semelhante ao Hashtable, exceto que HashMap é assíncrono e permite nulo, ou seja, valor nulo e chave nula. , mas ao tratar HashMap como uma Coleção (o métodovalues() pode retornar uma Coleção), o tempo gasto de suas suboperações de iteração é proporcional à capacidade do HashMap. Portanto, se o desempenho das operações iterativas for muito importante, não defina a capacidade inicial do HashMap muito alta ou o fator de carga muito baixo.
Classe WeakHashMap WeakHashMap é um HashMap aprimorado que implementa "referências fracas" para chaves. Se uma chave não for mais referenciada externamente, a chave poderá ser reciclada pelo GC.
Resumo <BR>Se operações como pilhas e filas estiverem envolvidas, você deve considerar usar List. Se precisar inserir e excluir elementos rapidamente, você deve usar LinkedList. Se precisar de acesso aleatório rápido aos elementos, você deve usar ArrayList.
Se o programa estiver em um ambiente de thread único, ou o acesso for realizado apenas em um thread, considere classes assíncronas, que são mais eficientes. Se vários threads puderem operar uma classe ao mesmo tempo, devem ser utilizadas classes sincronizadas.
Preste atenção especial ao funcionamento da tabela hash. O objeto usado como chave deve substituir corretamente os métodos equals e hashCode.
Tente retornar a interface em vez do tipo real, como retornar List em vez de ArrayList, para que, se você precisar substituir ArrayList por LinkedList no futuro, o código do cliente não precise ser alterado. Isso é programação para abstração.