Java集合(一)

一.概述

上一篇学习了集合的基本概述,了解集合接口的继承关系和接口中的基本功能。Java集合概述
这一篇学习集合中Collection接口的具体实现,首先看下类的继承关系。
Collection集合接口

二.具体集合

1.链表

其实数组也算是一种数据结构,但它不能很好的扩充容量。出现了以数组为基本的ArrayList类进行存储。它们共同的缺陷就是如果想要从数组中间插入或删除,都要进行数组的遍历,然后在插入或删除的位置,向前或向后移动其他元素的位置,这样导致效率不是很高。所以使用链表的数据结构进行存储能解决这一问题。当然链表也有缺陷,查询效率不如数组实现高。如果数据量比较小的情况下建议使用ArrayList进行增加和删除。

/**
 * 链表实例
 */
public class LinkedListDemo {
	public static void main(String[] args) {
		List<String> a = new LinkedList<>();
		a.add("a");
		a.add("b");
		a.add("c");

		List<String> b = new LinkedList<>();
		b.add("d");
		b.add("e");
		b.add("f");
		// ListIterator存在add方法而Iterator不存在add方法
		ListIterator<String> aIterator = a.listIterator();
		Iterator<String> bIterator = b.iterator();

		while (bIterator.hasNext()) {
			if (aIterator.hasNext()) {
				aIterator.next();
				// add 方法只依赖于迭代器的位置
				aIterator.add(bIterator.next());
			}
		}
		System.out.println(a);

		bIterator = b.iterator();
		while (bIterator.hasNext()) {
			bIterator.next();
			if (bIterator.hasNext()) {
				bIterator.next();
				// remove方法依赖于迭代器的状态
				bIterator.remove();
			}
		}
		System.out.println(b);

		// 移除a中存在的b
		a.removeAll(b);
		System.out.println(a);
		
		aIterator = a.listIterator();
		String s = aIterator.next();
		// 设置next之前的元素设置为3,set方法不被视为结构性改变。
		aIterator.set("3");
		System.out.println(a);
	}
}

注意:可以根据需要给容器附加许多的迭代器,但是这些迭代器只能读取列表。另外在单独附加一个既能读又能写的迭代器。

2.散列集

链表和数组的特点是有序的,在知道索引下表的情况下可以快速的查找等操作,如果不知道索引下标的情况就必须去遍历来进行查询,散列集的特点就是无序的,它可以在不知道的情况下进行快速的查询等操作。
散列表为每一个对象计算一个整数,称为散列码。如果是String类可以通过String类的hashCode方法来生成,如果是自定义类,就需要前面所学习的自定义hashCode方法。

/**
 * 散列集实例
 */
public class SetDemo {
	public static void main(String[] args) {
		Set<String> words = new HashSet<>();
		long totalTime = 0;

		try (Scanner in = new Scanner(System.in)) {
			while (in.hasNext()) {
				String word = in.next();
				long callTime = System.currentTimeMillis();
				words.add(word);
				callTime = System.currentTimeMillis() - callTime;
				totalTime += callTime;
			}
		}

		Iterator<String> iterator = words.iterator();
		for (int i = 1; i <= 20 && iterator.hasNext(); i++) {
			System.out.println(iterator.next());
		}

		System.out.println(". . .");
		System.out.println(words.size() + " distinct words " + totalTime + " milliseconds.");
	}
}

注意:

  • 在Java中,散列表用链表存储。Java8以后,桶满时会从链表改变为平衡二叉数存储。
  • 每个列表被称为桶,设置桶的默认值,可以增加查询效率,默认初始值为16。
  • 当桶满接近装填因子的值时,就会将所有的散列表再次进行散列,默认装填因子是75%。
  • set集合是无序不重复的,所以可以用于集合的去重处理。
3.树集

TreeSet类是一个有序集合,排序使用的是树结构(红黑树–这部分自行了解)

/**
 * 树结构实例
 */
public class TreeSetDemo {
	public static void main(String[] args) {
		SortedSet<Item> parts = new TreeSet<>();
		parts.add(new Item("a",123));
		parts.add(new Item("b",124));
		parts.add(new Item("c",122));

		System.out.println(parts);
		// 使用描述来进行排序
		// Java6以后,TreeSet实现了NavigableSet接口。(自行查询API)
		NavigableSet<Item> sortByDescription = new TreeSet<>(
				Comparator.comparing(Item::getDescription)
		);
		sortByDescription.addAll(parts);
		System.out.println(sortByDescription);
	}
}


class Item implements Comparable<Item> {

	private String description;
	private int partNumber;

	public Item(String description, int partNumber) {
		this.description = description;
		this.partNumber = partNumber;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public int getPartNumber() {
		return partNumber;
	}

	public void setPartNumber(int partNumber) {
		this.partNumber = partNumber;
	}

	@Override
	public String toString() {
		return "Item{" +
				"description='" + description + '\'' +
				", partNumber=" + partNumber +
				'}';
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		Item item = (Item) o;
		return partNumber == item.partNumber &&
				Objects.equals(description, item.description);
	}

	@Override
	public int hashCode() {
		return Objects.hash(description, partNumber);
	}

	@Override
	public int compareTo(Item o) {
		// 按照部件号来进行排序
		int diff = Integer.compare(partNumber,o.partNumber);
		return diff != 0 ? diff : description.compareTo(o.description);
	}
}
4.队列与双端队列
/**
 * 双端队列实例
 */
public class ArrayDequeDemo {
	public static void main(String[] args) {
		// 在Java6以后Deque接口,这个接口就是双端队列的顶级接口,由LinkedList和ArrayDeque来实现
		// 创建一个双端队列默认大小为16
		ArrayDeque<String> deque = new ArrayDeque<>();
		
		/*
		* 这是Queue接口的方法
		*/
		
		// 如果队列没满添加到队列并返回true;满了抛出异常
		deque.add("1");
		// 如果队列没满添加到队列并返回true;满了返回false
		deque.offer("2");
		// 如果队列不空,删除并返回这个队列头部的元素,是空的抛出异常
		deque.remove();
		// 如果队列不空,删除并返回这个队列头部的元素,是空的返回null
		deque.poll();
		// 如果队列不空,返回这个队列头部的元素,是空的抛出异常
		deque.element();
		// 如果队列不空,返回这个队列头部的元素,是空的返回null
		deque.peek();

		/*
		 * 这是Deque接口的方法
		 */
		
		// 添加到双端队列的头部或尾部 队列满了抛出异常
		deque.addFirst("1");
		deque.addLast("2");
		// 添加到双端队列的头部或尾部 队列满了返回false
		deque.offerFirst("1");
		deque.offerLast("2");
		// 如果队列不空,删除并返回头部或尾部的元素,为空抛出异常
		deque.removeFirst();
		deque.removeLast();
		// 如果队列不空,删除并返回头部或尾部的元素,为空返回null
		deque.pollFirst();
		deque.pollLast();
		// 如果队列不空,返回头部或尾部的元素,为空抛出异常
		deque.getFirst();
		deque.getLast();
		// 如果队列不空,返回头部或尾部的元素,为空返回null
		deque.peekFirst();
		deque.peekLast();
	}
}
5.优先级队列

队列中的元素可以按照任意的顺序插入,却总是按照排序的顺序检索。无论合适调用remove方法,总会获得当前优先级队列中最小的元素。


/**
 * 优先级队列
 */
public class PriorityQueueDemo {
	public static void main(String[] args) {
		PriorityQueue<LocalDate> queue = new PriorityQueue<>();
		queue.add(LocalDate.of(1998,9,1));
		queue.add(LocalDate.of(1991,12,1));
		queue.add(LocalDate.of(1992,8,1));
		queue.add(LocalDate.of(1995,11,1));
		// 不管显示的顺序如何,删除都会删除最小的元素
		System.out.println("Iterating over elements...");
		for (LocalDate date : queue) {
			System.out.println(date);
		}
		System.out.println("Removing elements...");
		while (!queue.isEmpty()) {
			System.out.println(queue.remove());
		}
	}
}

三.总结

这篇主要学习了Collection接口的一些具体集合,没种集合都有它自己的特点,在使用上要根据具体情况采取最适合的集合进行存储,这样会大大加快程序的运行效率。
下一篇学习映射类集合Map接口,也是比较常用的集合。
有些可能我理解的不够深刻,大家如果觉得我说的不够详细可以参考我的推荐书,详细的看一下。欢迎大家评论。第一时间我会回复大家。谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值