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

时间:2021-06-21 22:20:19

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.

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

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

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

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

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

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

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

  

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

// 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

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

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

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

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

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

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

  

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

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关系一样,红黑树结构控制存储。

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

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

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相等。

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

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}

  

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

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值的元素。相同的桶里边的元素之间是通过链表实现的,必须按顺序存储,故桶内的查找效率就会低了。

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

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

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