泛型和类型安全的容器

如果想建立一个Appel对象的容器,可以使用ArrayList,可以将ArrarList当作可以自动扩充自身尺寸的一个数组
如何使用ArrayList:创建一个实例,使用add()插入对象,然后用get()方法访问这些对象,这时候就需要使用索引,就像数组一样,但是不需要放扩招,ArrayList还有一个size()方法 (集合中的个数)

  1. class Apple{
  2. private static Long count;
  3. private final long id = count++;
  4. public long id(){
  5. return id;
  6. }
  7. }
  8. class Orange{}
  9. public class ApplesAndOrangeWithoutGenerics {
  10. public static void main(String[] args) {
  11. ArrayList apples = new ArrayList(); //没有申明保存的类型,此时保存的就是Object
  12. //随意集合里面可以添加Apple类型,也可以添加
  13. //Orange类型,但是在取出的时候得到的还是Object
  14. //类型,所以需要进行类型转换,但是Orange类型
  15. //无法转换成为Apple类型
  16. for (int i = 0; i < 3; i++){
  17. apples.add(new Apple());
  18. }
  19. apples.add(new Orange());
  20. for (int i = 0 ; i < apples.size();i++){
  21. ((Apple)apples.get(i)).id(); //orange只有在运行时报错
  22. }
  23. }
  24. }

如果使用泛型就可以在编译器就可以对将错误的类型放到容器中这个错误进行提示

  1. class Apple{
  2. private static long count;
  3. private final long id = count++;
  4. public long id(){
  5. return id;
  6. }
  7. }
  8. class Orange{}
  9. public class ApplesAndOrangeWithoutGenerics {
  10. public static void main(String[] args) {
  11. ArrayList<Apple> apples = new ArrayList<Apple>();//指定了集合的类型,此时集合里面
  12. //只可以放入Apple类型,否则会报错
  13. //并且在取出的时候也不需要类型转换
  14. for (int i = 0 ; i < 3; i ++){
  15. apples.add(new Apple());
  16. }
  17. for (int i = 0 ; i < apples.size();i++){
  18. System.out.println(apples.get(i).id());
  19. }
  20. for (Apple c : apples) { //如果不需要每个元素的索引的话,可以使用Foreach来
  21. //循环数组中的每个元素
  22. System.out.println(c.id());
  23. }
  24. }
  25. }

如果指定了某个类型作为泛型参数的时候,并不是只可以放入该类型的对象,向上转型也可以应用在这里

  1. class GrannySmith extends Apple{}
  2. class Gala extends Apple{}
  3. class Fuji extends Apple{}
  4. class Braeburn extends Apple{}
  5. public class GenericsAndUpcasting {
  6. public static void main(String[] args) {
  7. final ArrayList<Apple> apples = new ArrayList<>();
  8. apples.add(new Apple()); //Apple的子类也可以放置容器中
  9. apples.add(new Gala());
  10. apples.add(new Fuji());
  11. apples.add(new Braeburn());
  12. for (Apple apple : apples) {
  13. System.out.println(apple);
  14. }
  15. }
  16. }

基本概念

(1)Collection:一个独立元素的序列,这些元素都服从一种或者多种规则
①List:必须按照插入的顺序保存元素
②Set:不能有重复的元素
③Queue:按照排队规则来确定对象产生的顺序(通常和被取出的顺序相同)(可能取出之后就不在容器中了)
(2)Map:一组成对的“键值对”对象,允许使用键来查找值,它将数字和对象联系在了一起,映射表允许我们使用另一个对象来查找某个对象,也被称为关联数组

添加一组元素

Array.asList()方法接受一个数组或者是一个用逗号分隔的元素列表(使用可变参数),并且将其转换称为一个List对象
Collections.addAll()方法接受一个Collection对象,以及一个数组或者一个用逗号分隔的列表

  1. public class AddGroups {
  2. public static void main(String[] args) {
  3. Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));
  4. Integer[] moreInt = {6,7,8,9,10};
  5. collection.addAll(Arrays.asList(moreInt));
  6. Collections.addAll(collection , 11,12,13,14,15);
  7. Collections.addAll(collection,moreInt);
  8. List<Integer> list = Arrays.asList(16,17,18,19,20);
  9. list.set(1,99); // 下标为1的位置改为99
  10. }
  11. }

Array.asList()底层时数组,无法对其进行add(),delete()方法

容器的打印

  1. public class PrintingContainers {
  2. static Collection fill(Collection<String> collection){
  3. collection.add("rat");
  4. collection.add("cat");
  5. collection.add("dog");
  6. collection.add("dog");
  7. return collection;
  8. }
  9. static Map fill(Map<String,String> map){
  10. map.put("rat","Fuzzy");
  11. map.put("cat", "rags");
  12. map.put("dog", "Bosco");
  13. map.put("dog", "Spot");
  14. return map;
  15. }
  16. public static void main(String[] args) {
  17. System.out.println(fill(new ArrayList<String>()));
  18. System.out.println(fill(new LinkedList<String>()));
  19. System.out.println(fill(new HashSet<String>()));
  20. System.out.println(fill(new TreeSet<String>()));
  21. System.out.println(fill(new LinkedHashSet<String>()));
  22. System.out.println(fill(new HashMap<String,String>()));
  23. System.out.println(fill(new TreeMap<String,String>()));
  24. System.out.println(fill(new LinkedHashMap<String,String>()));
  25. }
  26. }

List

ArrayList:随机访问比LinkedList快,但是在中间插入删除元素没有LinkedList快
LinkedList:在List中间插入删除元素比较比ArrayList快,但是在随机访问方面没有ArrayList快
equals:确定一个元素是否属于List,或者发现他的索引,或者从List中移除某个元素,中间都使用的equals
例如两个String对象在完全一样的情况下是相等的,但是如果是自己创建的类的话,如果没有重写的话就算两个类内容相同,但是equals的话也是不想等的

  1. public class ArrayListDemo {
  2. public static void main(String[] args) {
  3. ArrayList<String> demo = new ArrayList<>();
  4. demo.add("haha");
  5. demo.add("hehe");
  6. demo.add("wuhu");
  7. demo.add("xixi");
  8. demo.add("asd");
  9. demo.add("keke");
  10. System.out.println(demo);
  11. demo.remove("wuhu");
  12. System.out.println(demo);
  13. System.out.println(demo.get(2));
  14. System.out.println(demo.indexOf("keke"));
  15. String s = "sout";
  16. System.out.println(demo.indexOf("sout"));
  17. System.out.println(demo.remove("sout"));
  18. System.out.println(demo.remove("xixi"));
  19. System.out.println(demo);
  20. demo.add(2,"huwu");
  21. System.out.println(demo);
  22. List<String> sub =demo.subList(1,4); //左闭右开
  23. System.out.println(sub);
  24. sub.set(2,"dsa"); //此时更改sub中的参数,demo中的也会被修改
  25. System.out.println("sub = " + sub);
  26. System.out.println("demo = " + demo); //sub 为 demo的一个视图
  27. //是否包含此元素 sub是包含String元素的List
  28. System.out.println(demo.contains(sub));
  29. System.out.println(demo.containsAll(sub));
  30. Collections.sort(sub);
  31. System.out.println("Sub = " +sub);
  32. System.out.println("demo = " + demo); //更改sub中的参数顺序,demo中的顺序也会改变
  33. final Random random = new Random(47);
  34. Collections.shuffle(sub,random); //将sub中的参数顺序进行打乱
  35. System.out.println(sub);
  36. System.out.println(demo);
  37. List<String> copy = new ArrayList<String>(demo);
  38. System.out.println(demo);
  39. System.out.println(copy);
  40. sub = Arrays.asList(demo.get(1),demo.get(4));
  41. System.out.println(sub);
  42. copy.retainAll(sub);
  43. System.out.println(copy);
  44. copy = new ArrayList<String>(demo);
  45. System.out.println(copy);
  46. copy.remove(2);
  47. System.out.println(copy);
  48. copy.removeAll(sub);
  49. System.out.println(copy);
  50. copy.set(1,"wuhu");
  51. System.out.println(sub);
  52. copy.addAll(1, sub);
  53. System.out.println(copy);
  54. System.out.println(demo.isEmpty());
  55. demo.clear();
  56. demo.add("wuhu");
  57. System.out.println(demo);
  58. demo.add("haha");
  59. demo.add("xixi");
  60. demo.add("hehe");
  61. demo.add("nene");
  62. System.out.println(demo);
  63. Object o = demo.toArray();
  64. String str = "whuu";
  65. int i = 20;
  66. System.out.println(str.equals(i));

迭代器

Iterator

首先迭代器是一个对象,它就是用来遍历并选择序列中的对象,迭代器被称为轻量级对象,而且JAVA中的迭代器只能够单项移动。
1 使用方法Iterator()要求容器返回一个Iterator,他将会放回序列的第一个元素
2 使用next()获取下一个元素
3 使用hasnext()来判断是否还有下一个元素
4 使用remove()来将新进返回的元素删除

  1. public class SimpleIteration {
  2. public static void main(String[] args) {
  3. List<Pet> pets = Pets.arrayList(12);
  4. Iterator<Pet> iterator = pets.iterator();
  5. while (iterator.hasNext()){
  6. Pet p = iterator.next();
  7. System.out.print(p.id() + ": " + p + " ");
  8. }
  9. System.out.println();
  10. for (Pet pet : pets) {
  11. System.out.print(pet.id() + ": " + pet + " ");
  12. }
  13. System.out.println();
  14. iterator = pets.iterator();
  15. for (int i = 0; i < 6; i++) {
  16. iterator.next();
  17. iterator.remove(); //将新近的元素进行删除
  18. }
  19. System.out.println(pets);
  20. }
  21. }

如果只是遍历,foreach也可以,如果想修改里面的元素,可以移除由next()产生的元素

  1. public class CrossContainerIteration {
  2. public static void display(Iterator<Pet> iterator){
  3. while (iterator.hasNext()){
  4. Pet p = iterator.next();
  5. System.out.print(p.id() + ": " + p + " ");
  6. }
  7. System.out.println();
  8. }
  9. public static void main(String[] args) {
  10. ArrayList<Pet> pets = Pets.arrayList(12);
  11. LinkedList<Pet> petLinkedList = new LinkedList<>(pets);
  12. HashSet<Pet> petHashSet = new HashSet<>(pets);
  13. TreeSet<Pet> petTreeSet = new TreeSet<>(pets);
  14. LinkedHashSet<Pet> petLinkedHashSet = new LinkedHashSet<>(pets);
  15. display(pets.iterator());
  16. display(petLinkedList.iterator());
  17. display(petHashSet.iterator());
  18. display(petTreeSet.iterator());
  19. display(petLinkedHashSet.iterator());
  20. }
  21. }

在display方法中,并没有返回的容器的类型信息,说明:iterator能够将遍历的操作和序列的结构相分离也可以说统一了对容器的访问方式

ListIterator

它是Iterator的一个子类型,它只可以用于List类型的访问,并且它可以双向移动,可以用set来替换它访问过的最后一个元素。

  1. public class ListIteration {
  2. public static void main(String[] args) {
  3. List<Pet> pets = Pets.arrayList(8);
  4. ListIterator<Pet> listIterator = pets.listIterator();
  5. while (listIterator.hasNext()){
  6. System.out.print(listIterator.next() + ", " +
  7. listIterator.nextIndex() + +listIterator.previousIndex() + " ");
  8. }
  9. System.out.println();
  10. while (listIterator.hasPrevious()){
  11. System.out.print(listIterator.previous() + ", " +
  12. listIterator.previousIndex() + listIterator.nextIndex() + " ");
  13. }
  14. System.out.println();
  15. System.out.println(pets);
  16. listIterator = pets.listIterator(3); //从索引为3的位置开始读
  17. while (listIterator.hasNext()){
  18. listIterator.next();
  19. listIterator.set(Pets.randomPet()); //可以边读边改,但是存在并发问题
  20. }
  21. System.out.println(pets);
  22. }
  23. }

LinkedList

在执行插入和删除的时候比ArrayList快,但是在随机读取方面没有ArrayList快,并且LinkedList中由让其完成栈,队列或者双端队列的方法。

  1. public class LinkedListFeature {
  2. public static void main(String[] args) {
  3. LinkedList<Pet> pets = new LinkedList<>(Pets.arrayList(12));
  4. System.out.println(pets);
  5. System.out.println(pets.getFirst());
  6. System.out.println(pets.get(5));
  7. System.out.println(pets.element());
  8. System.out.println(pets.indexOf(new Cymric()));
  9. System.out.println(pets.peek());
  10. System.out.println(pets.remove());
  11. System.out.println(pets);
  12. System.out.println(pets.removeFirst());
  13. System.out.println(pets);
  14. System.out.println(pets.poll());
  15. System.out.println(pets);
  16. System.out.println(pets.pollFirst());
  17. System.out.println(pets.add(new Rat())); //添加在尾部
  18. System.out.println(pets);
  19. System.out.println(pets.add(new Mutt()));
  20. System.out.println(pets);
  21. System.out.println(pets.offer(new Pug()));
  22. System.out.println(pets);
  23. pets.addLast(new Hamster());
  24. System.out.println(pets);
  25. System.out.println(pets.removeLast());
  26. System.out.println(pets);
  27. }
  28. }

栈使用LinkedList就可以

Set

Set最常被使用于测试归属性,很容易的询问某个对象是否在某个Set中,查找就成了Set中最重要的操作
Set具有和Collectioin完全一样的接口,并没有额外的功能,只是行为有些不同,Set是基于对象的值来判断归属性的

  1. public class SetOfInteger {
  2. public static void main(String[] args) {
  3. final Random random = new Random(47);
  4. Set<Integer> set = new HashSet<>();
  5. for (int i = 0; i < 10000; i++) {
  6. set.add(random.nextInt(20));
  7. }
  8. System.out.println(set);
  9. }
  10. }

如果想对结果进行排序,可以用TreeSet来代替TreeSet

  1. public class SortSetOfInteger {
  2. public static void main(String[] args) {
  3. TreeSet<Integer> integerTreeSet = new TreeSet<>();
  4. Random random = new Random();
  5. for (int i = 0; i < 10000; i++) {
  6. integerTreeSet.add(random.nextInt(20));
  7. }
  8. System.out.println(integerTreeSet);
  9. }
  10. }

Map

一组成对的“键值对”对象,允许使用键来查找值,它将数字和对象联系在了一起,映射表允许我们使用另一个对象来查找某个对象,也被称为关联数组

  1. public class Statistics {
  2. public static void main(String[] args) {
  3. final Random random = new Random();
  4. Map<Integer, Integer> ints = new HashMap<>();
  5. for (int i = 0; i < 1000; i++) {
  6. int r = random.nextInt(20);
  7. Integer freq = ints.get(r);
  8. ints.put(r,freq == null ? 1 : freq + 1);
  9. }
  10. System.out.println(ints);
  11. }
  12. }
  1. public class PetMap {
  2. public static void main(String[] args) {
  3. Map<String, Pet> petMap = new HashMap<>();
  4. petMap.put("My Cat", new Cat("Molly"));
  5. petMap.put("My Dog", new Dog("Ginger"));
  6. petMap.put("MyHamster", new Hamster("Bosco"));
  7. System.out.println(petMap);
  8. Pet dog = petMap.get("My Dog");
  9. System.out.println(dog);
  10. System.out.println(petMap.containsKey("My Dog"));
  11. System.out.println(petMap.containsValue(dog));
  12. }
  13. }

Queue

典型的先进先出的队列,事物放入的顺序和取出的顺序是相同的

  1. public class QueueDemo {
  2. public static void printQ(Queue queue){
  3. while (queue.peek()!= null){
  4. System.out.print(queue.remove() + " ");
  5. }
  6. System.out.println();
  7. }
  8. public static void main(String[] args){
  9. Queue<Integer> demo = new LinkedList<>();
  10. final Random random = new Random(47);
  11. for (int i = 0; i < 10; i++) {
  12. demo.add(random.nextInt(i + 10));
  13. printQ(demo);
  14. }
  15. Queue<Character> qc = new LinkedList<>();
  16. for (char c : "Hello World".toCharArray()) {
  17. qc.add(c);
  18. }
  19. printQ(qc);
  20. }
  21. }

PriorityQueue

优先级队列,声明下一个弹出的元素是最需要的元素(具有最高的优先级)
当在队列中使用offer来插入一个对象时,这个对象在队列中会被排序,可以提供自己的Comparator来修改这个顺序

  1. public class PriorityDemo {
  2. public static void main(String[] args) {
  3. PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
  4. final Random random = new Random(47);
  5. for (int i = 0; i < 10; i++) {
  6. priorityQueue.offer(random.nextInt(i + 10));
  7. }
  8. printQ(priorityQueue);
  9. List<Integer> integers = Arrays.asList(10, 3, 6, 8, 7, 9, 25, 16, 19, 22, 30);
  10. PriorityQueue<Integer> integerPriorityQueue = new PriorityQueue<>(integers);
  11. printQ(integerPriorityQueue);
  12. priorityQueue = new PriorityQueue<>(integers.size(), Collections.reverseOrder());
  13. priorityQueue.addAll(integers);
  14. printQ(priorityQueue);
  15. String str = "w a n g b o t a o s h i g e d a s h a b i ";
  16. List<String> strings = Arrays.asList(str.split(" "));
  17. PriorityQueue<String> stringPriorityQueue = new PriorityQueue<>(strings);
  18. printQ(stringPriorityQueue);
  19. stringPriorityQueue = new PriorityQueue<>(strings.size(), Collections.reverseOrder());
  20. stringPriorityQueue.addAll(strings);
  21. printQ(stringPriorityQueue);
  22. Set<Character> characters = new HashSet<>(); //消除重复的字母,Set中不可以有重复的
  23. for (char c : str.toCharArray()) {
  24. characters.add(c);
  25. }
  26. PriorityQueue<Character> characterPriorityQueue = new PriorityQueue<>(characters);
  27. printQ(characterPriorityQueue);
  28. }
  29. }

允许重复,并且值越小优先级越高,在String中,空格也有值,并且它的优先级比字母小

Collection和Iterator

首先,Collection时描述所有序列的根接口,因为要表示其他若干个接口的共性而出现的接口

  1. public class InterfaceVsIterator {
  2. public static void display(Iterator<Pet> iterator){
  3. while (iterator.hasNext()){
  4. Pet p = iterator.next();
  5. System.out.print(p.id() + ": " + p + " ");
  6. }
  7. System.out.println();
  8. }
  9. public static void display(Collection<Pet> collection){
  10. for (Pet pet : collection) {
  11. System.out.print(pet.id() + ": " + pet + " ");
  12. }
  13. System.out.println();
  14. }
  15. public static void main(String[] args) {
  16. List<Pet> petList = Pets.arrayList(10);
  17. Set<Pet> petHashSet = new HashSet<>(petList);
  18. Set<Pet> petsTreeSet = new TreeSet<>(petList);
  19. Map<String,Pet> petMap = new LinkedHashMap<>();
  20. String[] names = {"wh", "wgx", "wbt", "wgy", "ssn", "zmy", "hah", "wuhu", "hehe", "xixi"};
  21. for (int i = 0; i < names.length; i++) {
  22. petMap.put(names[i], petList.get(i));
  23. }
  24. display(petList);
  25. display(petHashSet);
  26. display(petsTreeSet);
  27. display(petList.iterator());
  28. display(petHashSet.iterator());
  29. display(petsTreeSet.iterator());
  30. System.out.println(petMap);
  31. System.out.println(petMap.keySet());
  32. display(petMap.values());
  33. display(petMap.values().iterator());
  34. }
  1. public class CollectionSequence extends AbstractCollection<Pet> {
  2. private Pet[] pets = Pets.createArray(8);
  3. @Override
  4. public Iterator<Pet> iterator() {
  5. return new Iterator<Pet>() {
  6. private int index = 0;
  7. @Override
  8. public boolean hasNext() {
  9. return index < pets.length;
  10. }
  11. @Override
  12. public Pet next() {
  13. return pets[index++];
  14. }
  15. };
  16. }
  17. @Override
  18. public int size() {
  19. return pets.length;
  20. }
  21. public static void main(String[] args) {
  22. final CollectionSequence pets = new CollectionSequence();
  23. display(pets);
  24. display(pets.iterator());
  25. }
  26. }

Foreach和迭代器

foreach应用于数组,并且可以应用于所有的Collection对象

  1. public class ForeachCollection {
  2. public static void main(String[] args) {
  3. Collection<String> strings = new LinkedList<>();
  4. Collections.addAll(strings, "Take me Way Home".split(""));
  5. for (String string : strings) {
  6. System.out.print(string);
  7. }
  8. }

适配器的惯用法

必须提供特定的接口以满足foreach语句,当有一个接口,并且需要另外一个接口的时候,可以编写适配器

  1. class ReversibleArrayList<T> extends ArrayList<T>{
  2. public ReversibleArrayList(Collection<T> c){
  3. super(c);
  4. }
  5. public Iterable<T> reversed(){
  6. return new Iterable<T>() {
  7. @Override
  8. public Iterator<T> iterator() {
  9. return new Iterator<T>() {
  10. int current = size()-1;
  11. @Override
  12. public boolean hasNext() {
  13. return current > -1;
  14. }
  15. @Override
  16. public T next() {
  17. return get(current--);
  18. }};}};}}
  19. public class AdapterMethodIdiom {
  20. public static void main(String[] args) {
  21. ReversibleArrayList<String> strings = new ReversibleArrayList<String>(
  22. Arrays.asList("To Be Or Not To Be".split(" ")));
  23. for (String string : strings) {
  24. System.out.print(string);
  25. }
  26. System.out.println();
  27. for (String s : strings.reversed()) {
  28. System.out.print(s);}}}