【Java】-NO.16.EBook.4.Java.1.008-【疯狂Java讲义第3版 李刚】- 集合/容器

 1.0.0 Summary

Tittle:【Java】-NO.16.EBook.4.Java.1.008-【疯狂Java讲义第3版 李刚】- 集合

Style:EBook

Series:Java

Since:2017-09-22

End:....

Total Hours:...

Degree Of Diffculty:2

Degree Of Mastery:2

Practical Level:2

Desired Goal:2

Archieve Goal:....

Gerneral Evaluation:...

Writer:kingdelee

Related Links:

http://www.cnblogs.com/kingdelee/

1.

 

 

1.Iterator在迭代的过程中,不允许添加/删除对象,可以修改对象

2.想要在迭代中过滤/删除某个元素,使用Predicate

public class PredicateTest
{
    public static void main(String[] args)
	{
		// 创建一个集合
		Collection books = new HashSet();
		books.add(new String("轻量级Java EE企业应用实战"));
		books.add(new String("疯狂Java讲义"));
		books.add(new String("疯狂iOS讲义"));
		books.add(new String("疯狂Ajax讲义"));
		books.add(new String("疯狂Android讲义"));
		// 使用Lambda表达式(目标类型是Predicate)过滤集合
		books.removeIf(ele -> ((String)ele).length() < 10);
		System.out.println(books);
	}
}

  

public class PredicateTest2
{
    public static void main(String[] args)
	{
		// 创建books集合、为books集合添加元素的代码与前一个程序相同。
		Collection books = new HashSet();
		books.add(new String("轻量级Java EE企业应用实战"));
		books.add(new String("疯狂Java讲义"));
		books.add(new String("疯狂iOS讲义"));
		books.add(new String("疯狂Ajax讲义"));
		books.add(new String("疯狂Android讲义"));
		// 统计书名包含“疯狂”子串的图书数量
		System.out.println(calAll(books , ele->((String)ele).contains("疯狂")));
		// 统计书名包含“Java”子串的图书数量
		System.out.println(calAll(books , ele->((String)ele).contains("Java")));
		// 统计书名字符串长度大于10的图书数量
		System.out.println(calAll(books , ele->((String)ele).length() > 10));
	}
	public static int calAll(Collection books , Predicate p)
	{
		int total = 0;
		for (Object obj : books)
		{
			// 使用Predicate的test()方法判断该对象是否满足Predicate指定的条件
			if (p.test(obj))
			{
				total ++;
			}
		}
		return total;
	}
}

3.Stream提供了常用的几个数据流的操作

public class IntStreamTest
{
    public static void main(String[] args)
	{
		IntStream is = IntStream.builder()
			.add(20)
			.add(13)
			.add(-2)
			.add(18)
			.build();
		// 下面调用聚集方法的代码每次只能执行一个
		System.out.println("is所有元素的最大值:" + is.max().getAsInt());
		System.out.println("is所有元素的最小值:" + is.min().getAsInt());
		System.out.println("is所有元素的总和:" + is.sum());
		System.out.println("is所有元素的总数:" + is.count());
		System.out.println("is所有元素的平均值:" + is.average());
		System.out.println("is所有元素的平方是否都大于20:"
			+ is.allMatch(ele -> ele * ele > 20));
		System.out.println("is是否包含任何元素的平方大于20:"
			+ is.anyMatch(ele -> ele * ele > 20));
		// 将is映射成一个新Stream,新Stream的每个元素是原Stream元素的2倍+1
		IntStream newIs = is.map(ele -> ele * 2 + 1);
		// 使用方法引用的方式来遍历集合元素
		newIs.forEach(System.out::println); // 输出41 27 -3 37
	}
}

中间方法:

filter(Predicate predicate):

mapToXxxx(ToXxxFunction mapper):一对一进行转换

peek(Consumer action):

distinct()::

sorted():

limit(long maxSize)

末端方法:

forEach(Consumer action):

toArray():

min():

max():

count():

anyMatch(Predicate predicate)

findFirst():

findAny();

public class CollectionStream
{
    public static void main(String[] args)
	{
		// 创建books集合、为books集合添加元素的代码与8.2.5小节的程序相同。
		Collection books = new HashSet();
		books.add(new String("轻量级Java EE企业应用实战"));
		books.add(new String("疯狂Java讲义"));
		books.add(new String("疯狂iOS讲义"));
		books.add(new String("疯狂Ajax讲义"));
		books.add(new String("疯狂Android讲义"));
		// 统计书名包含“疯狂”子串的图书数量
		System.out.println(books.stream().filter(ele->((String)ele).contains("疯狂")).count()); // 输出4
		// 统计书名包含“Java”子串的图书数量
		System.out.println(books.stream().filter(ele->((String)ele).contains("Java") ).count()); // 输出2
		// 统计书名字符串长度大于10的图书数量
		System.out.println(books.stream().filter(ele->((String)ele).length() > 10).count()); // 输出2
		// 先调用Collection对象的stream()方法将集合转换为Stream,
		// 再调用Stream的mapToInt()方法获取原有的Stream对应的IntStream
		books.stream().mapToInt(ele -> ((String)ele).length())// 调用forEach()方法遍历IntStream中每个元素
			.forEach(System.out::println);// 输出8  11  16  7  8

		List<Integer> list = new ArrayList<>();
		list.add(1);
		list.add(3);
		list.add(3);
		list.add(2);
		list.add(4);
		list.add(4);
		list.add(5);
		list.add(5);
		list.add(5);
		System.out.println("--------1");
		list.stream().filter(f -> f == 3).forEach(System.out::println);
		System.out.println("--------2");
		list.stream().distinct().forEach(System.out::println);
		System.out.println("--------3");
		list.stream().sorted().forEach(System.out::println);
		System.out.println("--------4");
		System.out.println(list.stream().min((a, b) -> a - b).get());
		System.out.println("--------5");
		list.stream().limit(5).forEach(System.out::println);
		System.out.println(list.stream().count());
		System.out.println(list.stream().anyMatch(a -> a == 5));
		System.out.println(list.stream().findAny().get());
		System.out.println(list.stream().findAny().get());
		list.stream().mapToInt(a -> a*10).forEach(System.out::println);
		list.stream().map(a -> a * a).forEach(System.out::println);
//		list.stream().flatMap((a, b) -> a * b).forEach(System.out::println);

	}
}

  

4. Set:

Set实际上就是Collection,只是不允许添加重复元素。

HashSet、TreeSet、EnumSet

4.1 HashSet:

Hash排序

非同步

可以存null

比较集合中的元素是否相等的充要条件是,对应的hashcode()与equals()都要相等

// 1.判断Set集合中两个对象相等的条件是,equals和hashcode都要一样。
// 类A的equals方法总是返回true,但没有重写其hashCode()方法
class A
{
    public boolean equals(Object obj)
	{
		return true;
	}
}
// 类B的hashCode()方法总是返回1,但没有重写其equals()方法
class B
{
	public int hashCode()
	{
		return 1;
	}
}
// 类C的hashCode()方法总是返回2,且重写其equals()方法总是返回true
class C
{
	public int hashCode()
	{
		return 2;
	}
	public boolean equals(Object obj)
	{
		return true;
	}
}
public class HashSetTest
{
	public static void main(String[] args)
	{
		HashSet books = new HashSet();
		// 分别向books集合中添加两个A对象,两个B对象,两个C对象
		books.add(new A());
		books.add(new A());
		books.add(new B());
		books.add(new B());
		books.add(new C());
		books.add(new C());
		books.forEach(System.out::println);
	}
}

//com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.B@1
//com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.B@1
//com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.A@610455d6
//com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.C@2
//com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.A@511d50c0

  

// 1. HashSet查找/删除元素的时候,是根据hashcode去操作的,所以有规律的重写hashcode可以避免某个撞桶
class R
{
    int count;
    int count2;
	public R(int count)
	{
		this.count = count;
	}

	public R(int count, int count2) {
		this.count = count;
		this.count2 = count2;
	}

//	public String toString()
//	{
//		return "R[count:" + count + "]";
//	}


	@Override
	public String toString() {
		return "R{" +
				"count=" + count +
				", count2=" + count2 +
				'}';
	}

	public boolean equals(Object obj)
	{
		if(this == obj)
			return true;
		if (obj != null && obj.getClass() == R.class)
		{
			R r = (R)obj;
			return this.count == r.count;
		}
		return false;
	}
	public int hashCode()
	{
		return this.count;
	}
}
public class HashSetTest2
{
	public static void main(String[] args)
	{
		HashSet hs = new HashSet();
		hs.add(new R(5, 1));
		hs.add(new R(-3, 2));
		hs.add(new R(9, 3));
		hs.add(new R(-2, 4));
		// 打印HashSet集合,集合元素没有重复
		System.out.println(hs);
		// 取出第一个元素
		Iterator it = hs.iterator();
		R first = (R)it.next();
		// 为第一个元素的count实例变量赋值
		first.count = -3;     // ①
		// 再次输出HashSet集合,集合元素有重复元素
		System.out.println(hs);
		// 删除count为-3的R对象
		hs.remove(new R(-3));    // ②
		// 可以看到被删除了一个R元素
		System.out.println(hs);
		System.out.println("hs是否包含count为-3的R对象?"
			+ hs.contains(new R(-3))); // 输出false
		System.out.println("hs是否包含count为-2的R对象?"
			+ hs.contains(new R(-2))); // 输出false
		System.out.println("hs是否包含count为5的R对象?"
				+ hs.contains(new R(5))); // 输出false
	}
}

  

6.LinkHashSet:

LinkHashSet是HashSet的子类,根据hashcode决定存储位置,并通过链表维护元素次序使得元素插入有序。故可以有序的迭代读取元素。

7.TreeSet:

TreeSet是SortedSet接口的实现类,采用红黑树结构存储。排序规则:自然排序、自定义排序。

应注意:

7.1 TreeSet中的对象,应该是同一类型或者父子关系,且实现了Comapble接口。

7.2 TreeSet中的对象,应实现Comaprable接口,否则再加入第二个元素时,因为排序会调用Comaprable所以会报错。

7.3 TreeSet判断是否为同一对象,取决于compareTo()是否返回0

class A1 implements Comparable{

	@Override
	public int compareTo(Object o) {
		return 0;
	}
}
class B1 extends A1{

}
public class TreeSetErrorTest2
{
    public static void main(String[] args)
	{
		TreeSet ts = new TreeSet();
		// 向TreeSet集合中添加两个对象
//		ts.add(new String("疯狂Java讲义"));
//		ts.add(new Date());   // ①
		ts.add(new A1());   // ①
		ts.add(new B1());   // ①
	}
}

  

// 1. 当Set中的对象影响compareTo的元素被修改后,对该对象的删除和查找都将失效,而其他未被修改的对象正常。故不宜修改。
class R2 implements Comparable
{
    int count;
	public R2(int count)
	{
		this.count = count;
	}
	public String toString()
	{
		return "R[count:" + count + "]";
	}
	// 重写equals方法,根据count来判断是否相等
	public boolean equals(Object obj)
	{
		if (this == obj)
		{
			return true;
		}
		if(obj != null && obj.getClass() == R2.class)
		{
			R2 r = (R2)obj;
			return r.count == this.count;
		}
		return false;
	}
	// 重写compareTo方法,根据count来比较大小
	public int compareTo(Object obj)
	{
		R2 r = (R2)obj;
		return count > r.count ? 1 :
			count < r.count ? -1 : 0;
	}
}
public class TreeSetTest3
{
	public static void main(String[] args)
	{
		TreeSet ts = new TreeSet();
		ts.add(new R2(5));
		ts.add(new R2(-3));
		ts.add(new R2(9));
		ts.add(new R2(-2));
		// 打印TreeSet集合,集合元素是有序排列的
		System.out.println(ts);    // ①
		// 取出第一个元素
		R2 first = (R2)ts.first();
		// 对第一个元素的count赋值
		first.count = 20;
		// 取出最后一个元素
		R2 last = (R2)ts.last();
		// 对最后一个元素的count赋值,与第二个元素的count相同
		last.count = -2;
		// 再次输出将看到TreeSet里的元素处于无序状态,且有重复元素
		System.out.println(ts);   // ②
		// 删除实例变量被改变的元素,删除失败
		System.out.println(ts.remove(new R2(-2)));   // ③
		System.out.println(ts);
		// 删除实例变量没有被改变的元素,删除成功
		System.out.println(ts.remove(new R2(5)));    // ④
		System.out.println(ts);
	}
}

  

// 1.定制排序
class M
{
    int age;
	public M(int age)
	{
		this.age = age;
	}
	public String toString()
	{
		return "M[age:" + age + "]";
	}
}
public class TreeSetTest4
{
	public static void main(String[] args)
	{
		// 此处Lambda表达式的目标类型是Comparator
		TreeSet ts = new TreeSet((o1 , o2) ->
		{
			M m1 = (M)o1;
			M m2 = (M)o2;
			// 根据M对象的age属性来决定大小,age越大,M对象反而越小
			return m1.age > m2.age ? -1
				: m1.age < m2.age ? 1 : 0;
		});
		ts.add(new M(5));
		ts.add(new M(-3));
		ts.add(new M(9));
		System.out.println(ts);
	}
}

  

8.EmunSet

EmunSet

enum Season
{
    SPRING,SUMMER,FALL,WINTER
}
public class EnumSetTest
{
	public static void main(String[] args)
	{
		// 创建一个EnumSet集合,集合元素就是Season枚举类的全部枚举值
		EnumSet es1 = EnumSet.allOf(Season.class);
		System.out.println(es1); // 输出[SPRING,SUMMER,FALL,WINTER]
		// 创建一个EnumSet空集合,指定其集合元素是Season类的枚举值。
		EnumSet es2 = EnumSet.noneOf(Season.class);
		System.out.println(es2); // 输出[]
		// 手动添加两个元素
		es2.add(Season.WINTER);
		es2.add(Season.SPRING);
		es2.add(Season.SPRING);
		System.out.println(es2); // 输出[SPRING,WINTER]
		// 以指定枚举值创建EnumSet集合
		EnumSet es3 = EnumSet.of(Season.SUMMER , Season.WINTER);
		System.out.println(es3); // 输出[SUMMER,WINTER]
		EnumSet es4 = EnumSet.range(Season.SUMMER , Season.WINTER);
		System.out.println(es4); // 输出[SUMMER,FALL,WINTER]
		// 新创建的EnumSet集合的元素和es4集合的元素有相同类型,
		// es5的集合元素 + es4集合元素 = Season枚举类的全部枚举值
		EnumSet es5 = EnumSet.complementOf(es4);
		System.out.println(es5); // 输出[SPRING]
	}
}

  

public class EnumSetTest2
{
    public static void main(String[] args)
	{
		Collection c = new HashSet();
		c.clear();
		c.add(Season.FALL);
		c.add(Season.SPRING);
		// 复制Collection集合中所有元素来创建EnumSet集合
		EnumSet enumSet = EnumSet.copyOf(c);   // ①
		System.out.println(enumSet); // 输出[SPRING,FALL]
		c.add("疯狂Java讲义");
		c.add("轻量级Java EE企业应用实战");
		// 下面代码出现异常:因为c集合里的元素不是全部都为枚举值
		enumSet = EnumSet.copyOf(c);  // ②
	}
}

  

各种Set的实现类比较:

8.1.在add(), get()操作,性能 HashSet > TreeSet,理由TreeSet需要额外的红黑树来维持次序。

8.2.在add(), delete()操作,性能 HashSet > LinkedHashSet,遍历操作,性能 HashSet < LinkedHashSet,理由 LinkedHashSet有链表维护次序。

8.3,EnumSet是性能最好的,只能保存同一种枚举类的值作为集合元素。

8.4.HashSet,TreeSet,EnumSet都不是线程安全的,同步时应使用类似:

TreeSet<Object> objects = new TreeSet<>();
Collections.synchronizedNavigableSet(objects);

9. List

1.根据元素的equals判断List中两个元素是否相等,如果重写某元素equals=true,则该元素与集合中的任意一元素恒等。

// 1.根据元素的equals判断List中两个元素是否相等,如果重写某元素equals=true,则该元素与集合中的任意一元素恒等。
class A
{
    public boolean equals(Object obj)
	{
		return true;
	}
}
public class ListTest2
{
	public static void main(String[] args)
	{
		List books = new ArrayList();
		books.add(new String("轻量级Java EE企业应用实战"));
		books.add(new String("疯狂Java讲义"));
		books.add(new String("疯狂Android讲义"));
		System.out.println(books);
		// 删除集合中A对象,将导致第一个元素被删除
		books.remove(new A());     // ①
		System.out.println(books);
		// 删除集合中A对象,再次删除集合中第一个元素
		books.remove(new A());     // ②
		System.out.println(books);
	}
}
//[轻量级Java EE企业应用实战, 疯狂Java讲义, 疯狂Android讲义]
//[疯狂Java讲义, 疯狂Android讲义]
//[疯狂Android讲义]

  

public class ListTest3
{
    public static void main(String[] args)
	{
		List books = new ArrayList();
		// 向books集合中添加4个元素
		books.add(new String("轻量级Java EE企业应用实战"));
		books.add(new String("疯狂Java讲义"));
		books.add(new String("疯狂Android讲义"));
		books.add(new String("疯狂iOS讲义"));
		// 使用目标类型为Comparator的Lambda表达式对List集合排序
		// [疯狂iOS讲义, 疯狂Java讲义, 疯狂Android讲义, 轻量级Java EE企业应用实战]
//		books.sort((o1, o2)->((String)o1).length() - ((String)o2).length());
		// [轻量级Java EE企业应用实战, 疯狂Android讲义, 疯狂Java讲义, 疯狂iOS讲义]
//		books.sort((o1, o2)->((String)o2).length() - ((String)o1).length());
		// [疯狂iOS讲义, 疯狂Java讲义, 疯狂Android讲义, 轻量级Java EE企业应用实战]
		books.sort(Comparator.comparing(String::length));
		System.out.println(books);
		// 使用目标类型为UnaryOperator的Lambda表达式来替换集合中所有元素
		// 该Lambda表达式控制使用每个字符串的长度作为新的集合元素
		books.replaceAll(ele->((String)ele).length());
		System.out.println(books); // 输出[7, 8, 11, 16]

	}
}

  

Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。

// 1. Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。 
public class ListIteratorTest
{
    public static void main(String[] args)
	{

		String[] books = {
			"疯狂Java讲义", "疯狂iOS讲义",
			"轻量级Java EE企业应用实战"
		};
		List bookList = new ArrayList();
		for (int i = 0; i < books.length ; i++ )
		{
			bookList.add(books[i]);
		}


		ListIterator lit = bookList.listIterator();
		while (lit.hasNext())
		{
			System.out.println(lit.next());
			lit.add("-------分隔符-------");
		}
		System.out.println("=======下面开始反向迭代=======");
		while(lit.hasPrevious())
		{
			System.out.println(lit.previous());
		}
	}
}

  

10. Vector Stack ArrayList ArrayDeque

10.1 Vector是线程安全的,ArrayList是线程不安全的,然而,要保证线程安全,只需使用Collections.synchronizedList()即可,故Vector没卵用。

10.2 Vector是古老的类,存在诸多缺点,性能低下,远不如ArrayList,所以Vector应不使用。

10.3 Stack是Vector的子类,模拟实现栈结构,然而远不如ArrayDeque,故Stack应不使用。

10.4 特别注意 Arrays.ArrayList返回的是一个固定长度的数组,是Arrays里边的一个静态内部类,不是util包的ArrayList,故不能使用add remove等方法。

11. Queue

11.1 队列不允许随机访问,使用的是FIFO(先进先出)策略操作存储。

11.2 Deque是双端队列的接口,可以使用实现类ArrayDeqeue LinkedList同时操作两端,ArrayDeqeue既是队列也是栈。

11.3 PriorityQueue,queue中的异端,采取元素的大小而非FIFO的策略进行存储。

对于ArrayDeque:

入栈:

push、addFirst :加头,无返回,null会异常。

offerFirst:加头,有返回值,null会异常。调用addFirst。

add:加头,返回boolean,null会异常。

offer、offerLast:加尾,返回boolean,null会异常。

出栈:

pop、removeFirst:取头,删除。null会异常。

peek、peekFirst:取头,不删除。null返null。

peekLast:取尾,不删除。null返null

public class PriorityQueueTest
{
    public static void main(String[] args)
	{
		PriorityQueue pq = new PriorityQueue();
		// 下面代码依次向pq中加入四个元素
		pq.offer(6);
		pq.offer(-3);
		pq.offer(20);
		pq.offer(18);
		// 输出pq队列,并不是按元素的加入顺序排列
		System.out.println(pq); // 输出[-3, 6, 20, 18]
		// 访问队列第一个元素,其实就是队列中最小的元素:-3
		System.out.println(pq.poll());
	}
}


public class LinkedListTest
{
    public static void main(String[] args)
	{
		LinkedList books = new LinkedList();
		// 将字符串元素加入队列的尾部
		books.offer("疯狂Java讲义");
		// 将一个字符串元素加入栈的顶部
		books.push("轻量级Java EE企业应用实战");
		// 将字符串元素添加到队列的头部(相当于栈的顶部)
		books.offerFirst("疯狂Android讲义");
		// 以List的方式(按索引访问的方式)来遍历集合元素
		for (int i = 0; i < books.size() ; i++ )
		{
			System.out.println("遍历中:" + books.get(i));
		}
		// 访问、并不删除栈顶的元素
		System.out.println(books.peekFirst());
		// 访问、并不删除队列的最后一个元素
		System.out.println(books.peekLast());
		// 将栈顶的元素弹出“栈”
		System.out.println(books.pop());
		// 下面输出将看到队列中第一个元素被删除
		System.out.println(books);
		// 访问、并删除队列的最后一个元素
		System.out.println(books.pollLast());
		// 下面输出:[轻量级Java EE企业应用实战]
		System.out.println(books);
	}
}

public class ArrayDequeStack
{
    public static void main(String[] args)
	{
		ArrayDeque stack = new ArrayDeque();
		// 依次将三个元素push入"栈"
		stack.push("1");
//		stack.push("3");
//		stack.push("4");
//		stack.push("2");
//		stack.push("5");

		// add与Off是一样的方法
		stack.addFirst("8");
		stack.offer("8");
		stack.add("8");
		stack.addFirst("8");
		stack.addLast("8");
		stack.offer("8");

		//
		System.out.println(stack);
		System.out.println(stack.peekLast());
		System.out.println(stack.pop());
		System.out.println(stack.peekLast());
		System.out.println(stack);
	}
}


public class ArrayDequeQueue
{
    public static void main(String[] args)
	{
		ArrayDeque queue = new ArrayDeque();
		// 依次将三个元素加入队列
		queue.offer("疯狂Java讲义");
		queue.offer("轻量级Java EE企业应用实战");
		queue.offer("疯狂Android讲义");
		// 输出:[疯狂Java讲义, 轻量级Java EE企业应用实战, 疯狂Android讲义]
		System.out.println(queue);
		// 访问队列头部的元素,但并不将其poll出队列"栈",输出:疯狂Java讲义
		System.out.println(queue.peek());
		// 依然输出:[疯狂Java讲义, 轻量级Java EE企业应用实战, 疯狂Android讲义]
		System.out.println(queue);
		// poll出第一个元素,输出:疯狂Java讲义
		System.out.println(queue.poll());
		// 输出:[轻量级Java EE企业应用实战, 疯狂Android讲义]
		System.out.println(queue);
	}
}

  

12. ArrayList LinkedList

ArrayList 基于数组的线性表,以一块连续内存区保存所有元素,具有较好的随机访问效率。遍历使用get获取元素。

LinkedList 基于链表的线性表,在插入、删除元素时具有较好效率。遍历时使用Iterator。

13.Map

 

13.1 HashMap Hashtable

Hashtable与Vector一样都是过时的玩意,同步也没卵用,用 Collections.synchronizedMap() 就能够使HashMap具备同步效果。

class A
{
    int count;
	public A(int count)
	{
		this.count = count;
	}
	// 根据count的值来判断两个对象是否相等。
	public boolean equals(Object obj)
	{
		if (obj == this)
			return true;
		if (obj != null && obj.getClass() == A.class)
		{
			A a = (A)obj;
			return this.count == a.count;
		}
		return false;
	}
	// 根据count来计算hashCode值。
	public int hashCode()
	{
		return this.count;
	}
}
class B
{
	// 重写equals()方法,B对象与任何对象通过equals()方法比较都返回true
	public boolean equals(Object obj)
	{
		return true;
	}
}
public class HashtableTest
{
	public static void main(String[] args)
	{
		Hashtable ht = new Hashtable();
		ht.put(new A(60000) , "疯狂Java讲义");
		ht.put(new A(87563) , "轻量级Java EE企业应用实战");
		ht.put(new A(1232) , new B());
		System.out.println(ht);
		// 只要两个对象通过equals比较返回true,
		// Hashtable就认为它们是相等的value。
		// 由于Hashtable中有一个B对象,
		// 它与任何对象通过equals比较都相等,所以下面输出true。
		System.out.println(ht.containsValue("测试字符串")); // ① 输出true
		// 只要两个A对象的count相等,它们通过equals比较返回true,且hashCode相等
		// Hashtable即认为它们是相同的key,所以下面输出true。
		System.out.println(ht.containsKey(new A(87563)));   // ② 输出true
		// 下面语句可以删除最后一个key-value对
		ht.remove(new A(1232));    //③
		System.out.println(ht);
	}
}

  

// 1.当用于equals判断的值被修改时,该元素就无法被操作
public class HashMapErrorTest
{
    public static void main(String[] args)
	{
		HashMap ht = new HashMap();
		// 此处的A类与前一个程序的A类是同一个类
		ht.put(new A(60000) , "疯狂Java讲义");
		ht.put(new A(87563) , "轻量级Java EE企业应用实战");
		System.out.println("--------------1:" + ht);
		// 获得Hashtable的key Set集合对应的Iterator迭代器
		Iterator it = ht.keySet().iterator();
		// 取出Map中第一个key,并修改它的count值
		A first = (A)it.next();
		first.count = 87563;   // ①
		// 输出{A@1560b=疯狂Java讲义, A@1560b=轻量级Java EE企业应用实战}
		System.out.println("--------------2:" + ht);
		// 只能删除没有被修改过的key所对应的key-value对
		ht.remove(new A(87563));

		System.out.println("--------------3:" + ht);
		// 无法获取剩下的value,下面两行代码都将输出null。
		System.out.println(ht.get(new A(87563)));   // ② 输出null
		System.out.println(ht.get(new A(60000)));   // ③ 输出null
	}
}
//--------------1:{com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@ea60=疯狂Java讲义, com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@1560b=轻量级Java EE企业应用实战}
//--------------2:{com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@1560b=疯狂Java讲义, com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@1560b=轻量级Java EE企业应用实战}
//--------------3:{com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@1560b=疯狂Java讲义}
//null
//null

  

 13.2 LinkedHashMap

13.2.1 LinkedHashMap 是 HashMap的子类,如同LinkedHashSet是HashSet的子类一样,用双向链表维护key-value的顺序,使得迭代的顺序与插入的顺序是一致的。

13.2.2 LinkedHashMap 不用像HashMap一样靠hash控制key-value顺序,同时有避免TreeMap增加的成本,因为要维护插入顺序,故插入速度低于HashMap,但迭代速度要优于HashMap

public class LinkedHashMapTest
{
    public static void main(String[] args)
	{
		LinkedHashMap scores = new LinkedHashMap();
		scores.put("语文" , 80);
		scores.put("英文" , 82);
		scores.put("数学" , 76);
		// 调用forEach方法遍历scores里的所有key-value对
		scores.forEach((key, value) -> System.out.println(key + "-->" + value));
	}
}

  

 14. Properties

Properties是Hashtable的子类

public class PropertiesTest
{
    public static void main(String[] args)
		throws Exception
	{
		Properties props = new Properties();
		// 向Properties中增加属性
		props.setProperty("username" , "yeeku");
		props.setProperty("password" , "123456");
		// 将Properties中的key-value对保存到a.ini文件中
		props.store(new FileOutputStream("a.ini")
			, "comment line");   //①
		// 新建一个Properties对象
		Properties props2 = new Properties();
		// 向Properties中增加属性
		props2.setProperty("gender" , "male");
		// 将a.ini文件中的key-value对追加到props2中
		props2.load(new FileInputStream("a.ini") );   //②
		System.out.println(props2);
	}
}

  

 15.SortedMap

SortedMap是Map的子类接口,TreeMap是接口SortedMap的实现类,与TreeSet的SortedSet关系一样,红黑树结构控制存储。

 

 1.定制排序,传入Comparator的实现类实现compare(a,b)的方法

 2.自然排序,让TreeMap中的key元素对象实现Comparable的compareTo(O o)方法

class R implements Comparable
{
    int count;
	public R(int count)
	{
		this.count = count;
	}
	public String toString()
	{
		return "R[count:" + count + "]";
	}
	// 根据count来判断两个对象是否相等。
	public boolean equals(Object obj)
	{
		if (this == obj)
			return true;
		if (obj != null	&& obj.getClass() == R.class)
		{
			R r = (R)obj;
			return r.count == this.count;
		}
		return false;
	}
	// 根据count属性值来判断两个对象的大小。
	public int compareTo(Object obj)
	{
		R r = (R)obj;
		return count > r.count ? 1 :
			count < r.count ? -1 : 0;
	}
}
// 1.定制排序,传入Comparator的实现类实现compare(a,b)的方法
// 2.自然排序,让TreeMap中的key元素对象实现Comparable的compareTo(O o)方法
public class TreeMapTest
{
	public static void main(String[] args)
	{
		TreeMap tm = new TreeMap((a, b) -> (int)b - (int)a);
		tm.put(new R(3) , "轻量级Java EE企业应用实战");
		tm.put(new R(-5) , "疯狂Java讲义");
		tm.put(new R(9) , "疯狂Android讲义");
		System.out.println(tm);
		// 返回该TreeMap的第一个Entry对象
		System.out.println(tm.firstEntry());
		// 返回该TreeMap的最后一个key值
		System.out.println(tm.lastKey());
		// 返回该TreeMap的比new R(2)大的最小key值。
		System.out.println(tm.higherKey(new R(2)));
		// 返回该TreeMap的比new R(2)小的最大的key-value对。
		System.out.println(tm.lowerEntry(new R(2)));
		// 返回该TreeMap的子TreeMap
		System.out.println(tm.subMap(new R(-1) , new R(4)));
	}
}

  

16.WeakHashMap

与HsahMap的区别在于,HashMap里边对key的存储是强引用,而WeakHashMap是弱引用。即进行GC后,WeakHashMap里边的key因为不是强引用,而有可能会回收。缓冲区的除外。

// 1.new String()只保留了弱引用,而""是字符串缓冲区的,不会被GC。
public class WeakHashMapTest
{
    public static void main(String[] args)
	{
		WeakHashMap whm = new WeakHashMap();
		// 将WeakHashMap中添加三个key-value对,
		// 三个key都是匿名字符串对象(没有其他引用)
		whm.put(new String("语文") , new String("良好"));
		whm.put(new String("数学") , new String("及格"));
		whm.put(new String("英文") , new String("中等"));
		//将 WeakHashMap中添加一个key-value对,
		// 该key是一个系统缓存的字符串对象。
		whm.put("java" , new String("中等"));    // ①
		// 输出whm对象,将看到4个key-value对。
		System.out.println(whm);
		// 通知系统立即进行垃圾回收
		System.gc();
		System.runFinalization();
		// 通常情况下,将只看到一个key-value对。
		System.out.println(whm);
	}
}
//{英文=中等, java=中等, 数学=及格, 语文=良好}
//{java=中等}

  

17.IdentityHashMap

IdentityHashMap 判断相等需要key1 == key2 严格相等才可以,而HashMap只需要key1和key2通过equals比较相等且hashcode相等。

public class IdentityHashMapTest
{
    public static void main(String[] args)
	{
		IdentityHashMap ihm = new IdentityHashMap();
		// 下面两行代码将会向IdentityHashMap对象中添加两个key-value对
		ihm.put(new String("语文") , 89);
		ihm.put(new String("语文") , 78);
		// 下面两行代码只会向IdentityHashMap对象中添加一个key-value对
		ihm.put("java" , 93);
		ihm.put("java" , 98);
		System.out.println(ihm);
	}
}
//{语文=78, java=98, 语文=89}

  

 

 18.EnumMap

Enum内部以数组实现,所以非常高效

enum Season
{
    SPRING,SUMMER,FALL,WINTER
}
public class EnumMapTest
{
	public static void main(String[] args)
	{
		// 创建EnumMap对象,该EnumMap的所有key都是Season枚举类的枚举值
		EnumMap enumMap = new EnumMap(Season.class);
		enumMap.put(Season.SUMMER , "夏日炎炎");
		enumMap.put(Season.SPRING , "春暖花开");
		System.out.println(enumMap);
	}
}

  

 桶概念:

HashMap和HashSet通过hash算法存储key元素,而这个key有可能会有重复的情况,所以用了一个集合桶去装这些重复的hash值的元素。相同的桶里边的元素之间是通过链表实现的,必须按顺序存储,故桶内的查找效率就会低了。

猜你喜欢

转载自www.cnblogs.com/kingdelee/p/7577634.html