10Java集合

推荐链接:

Java集合

终于有人把 HashMap 说清楚了,面试不再怕的!

集合继承体系图

img

img

对象数组

1、数组既可以存储基本数据类型,也可以存储引用类型。存储引用类型时的数组就叫对象数组。

2、案例:

img

3、对象数组的内存图解:

img

集合结构及特点

常用集合的特征

  i. Set集合:不能保存重复值,不保存元素加入的顺序。

  ii. List集合:可以保存重复值,保存元素加入的顺序。

  iii. Map集合:保存一个键值对(Key-Value),键不能重复,值可以重复

Set集合

  i. java.util.TreeSet类:集合中的元素以升序排序。创建集合不能指定集合的长度。

  ii. java.util.HashSet类:集合中的元素根据哈希值进行排序。创建集合时可以指定集合的长度,长度不够时默认以75%的比例增加长度。

List集合

  **i. ArrayList:线性数据结构。根据位置获得元素效率高,添加与删除元素时效率低。**创建集合时可以指定集合的长度。

  **ii. LinkedList:链表数据结构。添加与删除元素时效率高,根据位置获得元素时效率低。**创建集合时不能指定集合的长度。

  iii. Vector:功能与ArrayList完全一致。Vector是线程安全的,ArrayList是线程不安全的。

Map集合

  i. Hashtable:线程安全的。不允许使用null作为键或值。

  ii. HashMap:线程不安全的。允许使用null作为键或值。

TreeSet 和 TreeMap 共性 : 使用元素的自然顺序对元素进行排序,或者根据创建集合时提供的 Comparator 进行排序,具体取决于使用的构造方法。总之,元素或集合必须要有比较性

    a:自然排序(元素具备比较性)

      存储的元素所属的类实现自然排序接口:Comparable接口

    b:比较器排序(集合具备比较性)

      让集合构造方法接收Comparator的实现类对象

泛型

从JDK1.5开始出现

  i. 在后期绑定数据类型。

  ii. 如果不指定泛型,默认为Object类型。

  iii. 泛型只能为Object或Object的子类的类型。

  iv. 为泛型添加约束条件:泛型 extends 类

Collection(单列集合)

API中说到:

​ Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。

​ 一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。

​ 即:Collection:是集合的顶层接口,它的子体系有重复的,有唯一的,有有序的,有无序的。

​ JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。

​ 此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。

|– List(有序,可重复):保存元素加入的顺序(存储顺序和取出顺序一致),可以保存重复值

​ |– ArrayList:

​ 线性数据结构(底层数据结构是数组)。查询快,增删慢。线程不安全,效率高。创建集合时可以指定集合的长度。

​ |– Vector:

​ 线性数据结构(底层数据结构是数组)。查询快,增删慢。线程安全,效率低。功能与ArrayList完全一致。

​ |– LinkedList:

​ 链表数据结构(底层数据结构是链表)。查询慢,增删快。线程不安全,效率高。创建集合时不能指定集合的长度。

|– Set(无序,唯一):不保存元素加入的顺序(存储顺序和取出顺序不一定一致),不能保存重复值

​ |– HashSet:

​ 底层数据结构是哈希表(是一个元素为链表的数组)。集合中的元素根据哈希值进行排序。创建集合时可以指定集合的长度,长度不够时默认以75%的比例增加长度。

​ 哈希表依赖两个方法:hashCode()和equals()

​ 执行顺序:

​ 首先判断hashCode()值是否相同

​ 是:继续执行equals(),看其返回值

​ 是true:说明元素重复,不添加

​ 否false:就直接添加到集合

​ 否:就直接添加到集合

​ 最终:

​ 自动生成hashCode()和equals()即可

​ |– LinkedHashSet:底层数据结构由链表和哈希表组成。由链表保证元素有序。由哈希表保证元素唯一。

​ |– TreeSet类:

​ 底层数据结构是红黑树(是一个自平衡的二叉树)。集合中的元素以升序排序。创建集合不能指定集合的长度。

​ 如何保证元素唯一性呢?

​ 根据比较的返回值是否是0来决定

​ 如何保证元素的排序呢?

​ 两种方式

​ 自然排序(元素具备比较性)

​ 让元素所属的类实现Comparable接口

​ 比较器排序(集合具备比较性)

​ 让集合接收一个Comparator的实现类对象

Map(双列集合)

​ A:Map集合的数据结构仅仅针对键有效,与值无关。

​ B: 以键值对(Key-Value)形式存储元素,键唯一,值可重复

​ API中说到:

​ 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

|– HashMap:

​ 底层数据结构是哈希表。此实现不同步,线程不安全,效率高。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。

​ 哈希表依赖两个方法:hashCode()和equals()

​ 执行顺序:

​ 首先判断hashCode()值是否相同

​ 是:继续执行equals(),看其返回值

​ 是true:说明元素重复,不添加

​ 否false:就直接添加到集合

​ 否:就直接添加到集合

​ 最终:

​ 自动生成hashCode()和equals()即可

​ |– LinkedHashMap:

​ Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现不同步,线程不安全。

​ 哈希表保证元素唯一性。链表保证元素有序(存储和取出的顺序一致)

|– Hashtable:

​ 底层数据结构是哈希表。线程安全,效率低。不允许使用 null 值和 null 键。

​ 哈希表依赖两个方法:hashCode()和equals()

​ 执行顺序:

​ 首先判断hashCode()值是否相同

​ 是:继续执行equals(),看其返回值

​ 是true:说明元素重复,不添加

​ 否false:就直接添加到集合

​ 否:就直接添加到集合

​ 最终:

​ 自动生成hashCode()和equals()即可

|– TreeMap:

​ 基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

​ 此实现不同步,线程不安全。

​ 如何保证元素唯一性呢?

​ 根据比较的返回值是否是0来决定

​ 如何保证元素的排序呢?

​ 两种方式

​ 自然排序(元素具备比较性)

​ 让元素所属的类实现Comparable接口

​ 比较器排序(集合具备比较性)

​ 让集合接收一个Comparator的实现类对象

集合的选择

看需求。

​ 是否是键值对象形式:

​ 是:Map

​ 键是否需要排序:

​ 是:TreeMap

​ 否:HashMap

​ 不知道,就使用HashMap。

​ 否:Collection

​ 元素是否唯一:

​ 是:Set

​ 元素是否需要排序:

​ 是:TreeSet

​ 否:HashSet

​ 不知道,就使用HashSet

​ 否:List

​ 要安全吗:

​ 是:Vector(其实我们也不用它,了解多线程)

​ 否:ArrayList或者LinkedList

​ 增删多:LinkedList

​ 查询多:ArrayList

​ 不知道,就使用ArrayList

​ 不知道,就使用ArrayList

集合的常见方法及遍历方式

​ Collection:

​ add()

​ remove()

​ contains()

​ iterator()

​ size()

​ 遍历方式:

​ 增强for

​ 迭代器

​ |–List

​ get()

​ 遍历方式:

​ 普通for

​ |–Set

​ Map:

​ put()

​ remove()

​ containskey(),containsValue()

​ keySet()

​ get()

​ value()

​ entrySet()

​ size()

​ 遍历方式:

​ 根据键找值

​ 根据键值对对象分别找键和值

掌握

​ ArrayList,、LinkedList、HashSet、HashMap,

​ 存储字符串和自定义对象数据并遍历

​ 集合的嵌套遍历

集合(Collection)

集合的由来

  我们学习的是Java – 面向对象 – 操作很多对象 – 存储 – 容器(数组和StringBuffer) – 数组

  而数组的长度固定,所以不适合做变化的需求,Java就提供了集合供我们使用。

    我们学习的是面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,我们就必须把这多个对象进行存储。

    而要想存储多个对象,就不能是一个基本的变量,而应该是一个容器类型的变量,在我们目前所学过的知识里面,有哪些是容器类型的呢?

    数组和StringBuffer。但是呢?StringBuffer的结果是一个字符串,不一定满足我们的要求,所以我们只能选择数组,这就是对象数组。

    而对象数组又不能适应变化的需求,因为数组的长度是固定的,这个时候,为了适应变化的需求,Java就提供了集合类供我们使用。

集合和数组的区别

  A:长度

    数组长度固定

    集合长度可变

  B: 存储的数据类型

    数组存储的数据可以是基本类型,也可以是引用类型,必须是同一种类型的元素。

    集合存储的数据只能是引用类型, 可存储不同引用类型的元素。(例如:Student类型,Teacher类型)

  C:元素内容

    数组只能存储同一种类型的元素。

    集合可存储不同引用类型的元素(其实集合一般存储的也是同一种类型),(例如:Student类型,Teacher类型)

集合的继承体系结构

  由于需求不同,Java就提供了不同的集合类。这些集合类的*数据结构(数据的存储方式)*不同,但是它们都是要提供 存储、判断、获取 等功能。

  我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。

  API中说到:

    Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素

    一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。

      即:Collection:是集合的顶层接口,它的子体系有重复的,有唯一的,有有序的,有无序的。

    JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。

    此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。

  重点学习:

      Collection

        |–List

          |–ArrayList

          |–Vector

          |–LinkedList

        |–Set

          |–HashSet

          |–TreeSet

Collection功能

A:添加功能

1
2
3
4
  boolean add(E e):确保此 collection 包含指定的元素(可选操作)。
    boolean add(Object obj):添加一个元素。
  boolean addAll(Collection<? extends E> c):将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
    boolean addAll(Collection c):添加一个集合的元素。

B:删除功能

1
2
3
4
  void clear():移除此 collection 中的所有元素(可选操作)。//移除所有元素
  boolean remove(Object o):从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。//移除一个元素(执行一次移除一个)
  boolean removeAll(Collection<?> c):移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
    boolean removeAll(Collection c):移除一个集合的元素(只要有一个元素被移除了,就返回true。)

C:判断功能

1
2
3
4
  boolean contains(Object o):如果此 collection 包含指定的元素,则返回 true//判断集合中是否包含指定的元素
  boolean containsAll(Collection<?> c):如果此 collection 包含指定 collection 中的所有元素,则返回 true
    boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(只有包含所有的元素,才叫包含,才会返回true)
    boolean isEmpty():如果此 collection 不包含元素,则返回 true//判断集合是否为空(指元素为空,不是对象为空)。该方法是通过对象调用的,若对象为空就不能调用方法了。

D:获取功能

1
2
3
4
  Iterator<E> iterator():返回在此 collection 的元素上进行迭代的Iterator(迭代器)。集合的专用遍历方式。(重点)
      E next():返回迭代的下一个元素。抛出: NoSuchElementException - 没有元素可以迭代。
        Object next():获取元素,并移动到下一个位置。不要多次使用it.next()方法,因为每次使用都是访问一个对象。
        boolean hasNext():如果仍有元素可以迭代,则返回 true

E:长度功能

​ int size():返回此 collection 中的元素数。

​ 面试题:数组有没有length()方法呢?字符串有没有length()方法呢?集合有没有length()方法呢?

1
2
3
4
5
6
7
String str = "";
String[] strArr = {};
ArrayList<String> list = new ArrayList<>();

str.length();
int a = strArr.length; // 必须有int类型变量接收
list.size();

F:交集功能(了解)

1
2
  boolean retainAll(Collection<?> c):仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。// 取交集,
    boolean retainAll(Collection c)

  思考元素去哪了,返回的boolean又是什么意思呢?
    解:假设有两个集合A,B。A对B做交集,最终的结果保存在A中,B不变。返回值表示的是A是否发生过改变,改变返回true。

G:把集合转数组(了解)

1
2
  Object[] toArray():返回包含此 collection 中所有元素的数组。//元素是任意对象类型,所以是以对象形式接收
  <T> T[] toArray(T[] a):返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。

测试不带All的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 测试不带All的方法
public class CollectionDemo {
public static void main(String[] args) {
// 创建集合对象
// Collection c = new Collection(); // 错误,因为接口不能实例化
Collection<String> c = new ArrayList<String>();

// boolean add(Object obj):添加一个元素
System.out.println("add:" + c.add("hello")); // 看源码可知永远返回true,说明可以存重复的元素。
c.add("hello");
c.add("world");
c.add("java");

// void clear():移除所有元素
// c.clear();
System.out.println("c:" + c); // c:[hello, hello, world, java]

// boolean remove(Object o):移除一个元素
System.out.println("remove:" + c.remove("hello")); // remove:true(一次移除一个)
System.out.println("remove:" + c.remove("javaee")); // remove:false
System.out.println("c:" + c); // c:[hello, world, java]

// boolean contains(Object o):判断集合中是否包含指定的元素
System.out.println("contains:" + c.contains("hello")); // contains:true
System.out.println("contains:" + c.contains("android")); // contains:false

// boolean isEmpty():判断集合是否为空(指元素是否为空)
System.out.println("isEmpty:" + c.isEmpty()); // isEmpty:false
// int size():元素的个数
System.out.println("size:" + c.size()); // size:3
}
}

测试带All的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*测试带All的方法
boolean addAll(Collection<? extends E> c):将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
boolean addAll(Collection c):添加一个集合的元素。

boolean removeAll(Collection<?> c):移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
boolean removeAll(Collection c):移除一个集合的元素(只要有一个元素被移除了,就返回true。)

boolean containsAll(Collection<?> c):如果此 collection 包含指定 collection 中的所有元素,则返回 true。
boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(只有包含所有的元素,才叫包含,才会返回true)

boolean retainAll(Collection<?> c):仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?
*/
public class CollectionDemo {
public static void main(String[] args) {
// 创建集合1
Collection<String> c1 = new ArrayList<String>();
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c1.add("abc4");
System.out.println("c1:" + c1); // c1:[abc1, abc2, abc3, abc4]

// 创建集合2
Collection<String> c2 = new ArrayList<String>();
// c2.add("abc1");
// c2.add("abc2");
// c2.add("abc3");
c2.add("abc4");
c2.add("abc5");
c2.add("abc6");
c2.add("abc7");
System.out.println("c2:" + c2); // c2:c2:[abc4, abc5, abc6, abc7]

// boolean addAll(Collection c):添加一个集合的元素
System.out.println("addAll:" + c1.addAll(c2));// addAll:true
System.out.println("c1:" + c1); // c1:[abc1, abc2, abc3, abc4, abc4, abc5, abc6, abc7]

// boolean removeAll(Collection c):移除一个集合的元素(只要有一个元素被移除了,就返回true。)
System.out.println("removeAll:" + c1.removeAll(c2));// removeAll:true
System.out.println("c1:" + c1);// c1:[abc1, abc2, abc3]

// boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(只有包含所有的元素,才叫包含,才会返回true)
c1.add("abc4");
System.out.println("c1:" + c1);// c1:[abc1, abc2, abc3, abc4]
System.out.println("c2:" + c2);// c2:[abc4, abc5, abc6, abc7]
System.out.println("containsAll:" + c1.containsAll(c2));// containsAll:false

// boolean retainAll(Collection c):返回的boolean又是什么意思呢?
// 假设有两个集合A,B。A对B做交集,最终的结果保存在A中,B不变。返回值表示的是A是否发生过改变。
System.out.println("c1:" + c1);// c1:[abc1, abc2, abc3, abc4]
System.out.println("c2:" + c2);// c2:[abc4, abc5, abc6, abc7]
// c1.remove("abc4");
System.out.println("retainAll:" + c1.retainAll(c2));// retainAll:true
System.out.println("c1:" + c1);// c1:[abc4]
}
}

Collection集合遍历

其实就是依次获取集合中的每一个元素。

  A:把集合转数组(了解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
* 把集合转成数组,可以实现集合的遍历
* Object[] toArray():返回包含此 collection 中所有元素的数组。元素是任意对象类型,所以是以对象形式接收。
*/
public class CollectionDemo {
public static void main(String[] args) {
// 创建集合对象
Collection<Object> c = new ArrayList<Object>();
// 添加元素
c.add("hello"); // Object obj = "hello"; 向上转型
c.add((Object) "world");
c.add("java");

// 遍历
Object[] objs = c.toArray();
for (int x = 0; x < objs.length; x++) {
// System.out.println(objs[x]);// hello \n world \n java \n
// 我知道元素是字符串,我在获取到元素的的同时,还想知道元素的长度。
// System.out.println(objs[x] + "---" + objs[x].length());//
// 错误做法,原因是Object中没有length()方法
// 我们要想使用字符串的方法,就必须把元素还原成字符串
String s = (String) objs[x]; // 向下转型
System.out.println(s + "---" + s.length());// hello---5 \n world---5 \n java---4 \n
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/*
* 练习:用集合存储5个学生对象,并把学生对象进行遍历。
* 分析:
* A:创建学生类
* B:创建集合对象
* C:创建学生对象
* D:把学生添加到集合
* E:把集合转成数组
* F:遍历数组
*/
public class StudentDemo {
public static void main(String[] args) {
Collection<Object> c = new ArrayList<Object>();
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("风清扬", 30);
Student s3 = new Student("令狐冲", 33);
Student s4 = new Student("武鑫", 25);
Student s5 = new Student("刘晓曲", 22);

c.add(s1); // Object obj = s1; 向上转型
c.add((Object) s2);
c.add(s3);
c.add(s4);
c.add(s5);

Object[] objs = c.toArray();
for (int x = 0; x < objs.length; x++) {
// System.out.println(objs[x]);// cn.cast.Student@15db9742
// 上一行是因为Student类中没重写toStirng()方法
// System.out.println(objs[x].getName());//错误,objs[x]不是Student类型,是Object类型
Student s = (Student) objs[x];
System.out.println(s.getName() + "---" + s.getAge());// 林青霞---27 \n....
}
}
}

class Student {
private String name;
private int age;

public Student() {
super();
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

  B:迭代器(集合专用方式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
* Iterator<E> iterator():返回在此 collection 的元素上进行迭代的Iterator(迭代器)。集合的专用遍历方式
* E next():返回迭代的下一个元素。抛出:NoSuchElementException - 没有元素可以迭代。
* 不要多次使用it.next()方法,因为每次使用都是访问一个对象。
* boolean hasNext():如果仍有元素可以迭代,则返回 true。
*/
public class IteratorDemo {
public static void main(String[] args) {
// 创建集合对象
Collection<Object> c = new ArrayList<Object>();
// 添加元素
c.add("hello"); // Object obj = "hello"; 向上转型
c.add((Object) "world");
c.add("java");

// Iterator iterator():迭代器,集合的专用遍历方式
Iterator<Object> it = c.iterator(); // Iterator是接口,实际返回的肯定是子类对象,这里是多态
Object obj = it.next();// Object next():获取元素,并移动到下一个位置。
System.out.println(obj);
while (it.hasNext()) {
// System.out.println(it.next());// hello \n world \n java \n
// 注意:String类型特殊,若Collection中存的是Object(描述可能有问题,理解就好),上面输出的应该是这样的:cn.cast.Student@15db9742
// System.out.println(it.next().length());// 错误做法,原因是Object中没有length()方法
// it.next()获取的是Object类型,我们要输出String类型,就需要转型。
String s = (String) it.next();// 向下转型
System.out.println(s + "---" + s.length());// hello---5 \n world---5 \n java---4 \n
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/*
* 练习:用集合存储5个学生对象,并把学生对象进行遍历。用迭代器遍历。
*/
public class IteratorTest {
public static void main(String[] args) {
Collection<Object> c = new ArrayList<Object>();
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("风清扬", 30);
Student s3 = new Student("令狐冲", 33);

c.add(s1); // Object obj = s1; 向上转型
c.add((Object) s2);
c.add(s3);

Iterator<Object> it = c.iterator();
while (it.hasNext()) {
// System.out.println(it.next());// cn.cast.Student@15db9742
// 是因为Student类中没重写toString()方法
// System.out.println(it.next().getName());//错误,it.next()得到的不是Student类型,是Object类型。
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());// 林青霞---27 \n...
// 注意:不要多次使用it.next()方法。集合中元素是偶数个不会报错(拿到的姓名和年龄对不上),奇数个就会报错。
// System.out.println(((Student) it.next()).getName() + "---" + ((Student)
// it.next()).getAge());// NoSuchElementException
}

// 使用for循环更好,因为对象是在for循环里面创建的,循环结束 it2 对象就已经是垃圾了,所以它的效率要高
for (Iterator<Object> it2 = c.iterator(); it2.hasNext();) {
Student s = (Student) it2.next();
System.out.println(s.getName() + "---" + s.getAge());// 林青霞---27 \n...
}
}
}

class Student {
private String name;
private int age;

public Student() {
super();
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

迭代器

​ 是集合获取元素的方式。

​ 是依赖于集合而存在的。

​ 迭代器的原理和源码。

    a:为什么定义为了一个接口而不是实现类?

    b:看了看迭代器的内部类实现。

  迭代器使用图解和原理解析:

img

  迭代器的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public interface Interator {
public abstract boolean hasNext();
public abstract Object next();
}

public interface Iterable {
Iterator<T> iterator();
}

public interface Collection extends Iterable {
Iterator<E> iterator();
}

public interface List extends Collection {
Iterator<E> iterator();
}

public class ArrayList implements List {
public Iterator<E> iterator() {
return new Itr();
}

// 内部类
private class Itr implements Iterator<E> {
public boolean hasNext() {}
public E next() {} // 把 E 看做 Object :public Object next(){}
}
}

//我们每次使用的动作
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Iterator it = c.iterator(); // new Itr();
while(it.hasNext()) {
String s = (String)it.next();
System.out.println(s);
}

Collection集合案例

遍历方式:迭代器

  集合的操作步骤:

    A:创建集合对象

    B:创建元素对象

    C:把元素添加到集合

    D:遍历集合

  A:存储字符串并遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class CollectionDemo {
public static void main(String[] args) {
// 创建集合对象
Collection<String> c = new ArrayList<String>();

// 创建并添加元素
c.add("hello");
c.add("world");
c.add("java");

// 遍历集合
// 通过集合对象获取迭代器对象
Iterator<String> it = c.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}

  B:存储自定义对象并遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class StudentDemo {
public static void main(String[] args) {
// 创建集合对象
Collection<Student> c = new ArrayList<Student>();

// 创建学生对象
Student s1 = new Student("貂蝉", 25);
Student s2 = new Student("小乔", 16);
Student s3 = new Student("黄月英", 20);
Student s4 = new Student();
s4.setName("大乔");
s4.setAge(26);

// 添加元素
c.add(s1);
c.add(s2);
c.add(s3);
c.add(s4);
c.add(new Student("孙尚香", 18)); // 匿名对象

// 遍历集合
Iterator<Student> it = c.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

集合(List)

List集合的特点

List:保存元素加入的顺序(存储顺序和取出顺序一致),可以保存重复值

|– ArrayList:线性数据结构(底层数据结构是数组)。查询快,增删慢。线程不安全,效率高。创建集合时可以指定集合的长度。

|– Vector:线性数据结构(底层数据结构是数组)。查询快,增删慢。线程安全,效率低。功能与ArrayList完全一致。

|– LinkedList:链表数据结构(底层数据结构是链表)。查询慢,增删快。线程不安全,效率高。创建集合时不能指定集合的长度。

Collection的子接口

  有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

  与 set 不同,列表通常允许重复的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//存储字符串并遍历
public class ListDemo {
public static void main(String[] args) {
// 创建集合对象
List<String> list = new ArrayList<String>();//

// 存储元素
list.add("hello");// ArrayList类中的add()永远返回true,所以可重复
list.add("world");
list.add("java");
list.add("javaee");
list.add("android");
list.add("javaee");
list.add("android");

// 遍历集合
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//存储自定义对象并遍历
public class ListDemo {
public static void main(String[] args) {
// 创建集合对象
List<Student> list = new ArrayList<Student>();

// 创建学生对象
Student s1 = new Student("白骨精", 30);
Student s2 = new Student("蜘蛛精", 40);
Student s3 = new Student("观音姐姐", 22);

// 把学生对象添加到集合对象中
list.add(s1);
list.add(s2);
list.add(s3);

// 遍历
Iterator<Student> it = list.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

List特有功能

E 看成Object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  A:添加功能
    void add(int index, E element):在列表的指定位置插入指定元素(可选操作)。将当前处于该位置的元素(如果有的话)和所有后续元素向右移动(在其索引中加 1)。

  B:删除功能
    E remove(int index):移除列表中指定位置的元素(可选操作)。将所有的后续元素向左移动(将其索引减 1)。返回从列表中移除的元素。
    boolean remove(Object o):从此列表中移除第一次出现的指定元素(如果存在)(可选操作)。如果列表不包含元素,则不更改列表。

  C:获取功能
    E get(int index):返回:列表中指定位置的元素。

  D:列表迭代器(List集合特有的迭代器)
    ListIterator<E> listIterator():返回此列表元素的列表迭代器(按适当顺序)。
      boolean hasPrevious():返回: 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true
      E previous():返回: 列表中的上一个元素。 抛出: NoSuchElementException - 如果没有可迭代的上一个元素

  E:修改功能
    E set(int index, E element):用指定元素替换列表中指定位置的元素(可选操作)。返回:以前在指定位置的元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ListDemo {
public static void main(String[] args) {
// 创建集合对象
List<String> list = new ArrayList<String>();

// 添加元素
list.add("hello");
list.add("world");
list.add("java");

// void add(int index, E element):在指定位置添加元素
// list.add(1, "android"); //没有问题
// list.add(3, "javaee"); //没有问题
// list.add(4, "javaee"); // IndexOutOfBoundsException

// Object get(int index):获取指定位置的元素
// System.out.println("get:" + list.get(1)); // get:world
// System.out.println("get:" + list.get(3)); // IndexOutOfBoundsException

// Object remove(int index):根据索引删除元素,返回被删除的元素
// System.out.println("remove:" + list.remove(1));
// System.out.println("remove:" + list.remove(11)); // IndexOutOfBoundsException

// Object set(int index,Object element):根据索引修改元素,返回被修饰的元素
System.out.println("set:" + list.set(1, "javaee")); // set:world
System.out.println("list:" + list);
}
}

List特有遍历功能

  A:由size()和get()结合。

  B:代码演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 存储字符串并遍历
public class ListDemo {
public static void main(String[] args) {
// 创建集合对象
List<String> list = new ArrayList<String>();

// 创建并添加元素
list.add("hello");
list.add("world");
list.add("java");

// 迭代器遍历(任何集合都具有的遍历方式)
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}

// List集合的特有遍历功能
for (int x = 0; x < list.size(); x++) {
String s = (String) list.get(x);
System.out.println(s);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//存储自定义对象并遍历
public class ListDemo {
public static void main(String[] args) {
// 创建集合对象
List<Student> list = new ArrayList<Student>();

// 创建学生对象
Student s1 = new Student("林黛玉", 18);
Student s2 = new Student("刘姥姥", 88);
Student s3 = new Student("王熙凤", 38);

// 把学生添加到集合中
list.add(s1);
list.add(s2);
list.add(s3);

// 迭代器遍历(任何集合都具有的遍历方式)
Iterator<Student> it = list.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());
}

// 普通for循环
for (int x = 0; x < list.size(); x++) {
Student s = (Student) list.get(x);
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

列表迭代器特有功能

​ 了解。可以逆向遍历,但是要先正向遍历,所以无意义,基本不使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*
* 列表迭代器:
* ListIterator<E> listIterator():List集合特有的迭代器
* 该迭代器继承了Iterator迭代器,所以,就可以直接使用hasNext()和next()方法。
* 特有功能:
* E previous():获取上一个元素
* boolean hasPrevious():判断是否有元素
* 注意:ListIterator可以实现逆向遍历,但是必须先正向遍历,才能逆向遍历,所以一般无意义,不使用。
*/
public class ListIteratorDemo {
public static void main(String[] args) {
// 创建List集合对象
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");

// ListIterator listIterator()
ListIterator<String> lit = list.listIterator(); // 子类对象
while (lit.hasNext()) {
String s = (String) lit.next();
System.out.println(s);
} // 该迭代器继承了Iterator迭代器,所以,就可以直接使用hasNext()和next()方法。

// System.out.println(lit.previous());
// System.out.println(lit.previous());
// System.out.println(lit.previous());
// System.out.println(lit.previous());// NoSuchElementException

while (lit.hasPrevious()) {
String s = (String) lit.previous();
System.out.println(s);
}

// 迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}

并发修改异常

​ ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

  A:出现的现象

    迭代器遍历集合过程中,通过集合对象修改集合元素。

  B:原因

    迭代器是依赖于集合的,而集合的改变迭代器并不知道。所以,迭代器遍历元素的过程中,通过集合是不能修改元素的。

  C:解决方案

    a:迭代器遍历,迭代器修改(ListIterator)

      元素添加在刚才迭代的位置

    b:集合遍历,集合修改(用for循环加上List集合的size()和get()方法,Collection集合没有get()方法)

      元素添加在集合的末尾

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//判断集合里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现。
public class ListIteratorDemo {
public static void main(String[] args) {
// 创建List集合对象
List<String> list = new ArrayList<String>();

// 添加元素
list.add("hello");
list.add("world");
list.add("java");

// 迭代器遍历
// Iterator<String> it = list.iterator();
// while (it.hasNext()) {
// String s = (String) it.next();
// System.out.println(s);
// if ("world".equals(s)) {
// list.add("javaee"); // java.util.ConcurrentModificationException
// }
// }

// 方式1:迭代器迭代元素,迭代器修改元素
// 而Iterator迭代器却没有添加功能,所以我们使用其子接口ListIterator
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
String s = (String) lit.next();
if ("world".equals(s)) {
lit.add("javaee");
}
System.out.println(s);
}

// 方式2:集合遍历元素,集合修改元素(普通for)
for (int x = 0; x < list.size(); x++) {
String s = (String) list.get(x);
if ("world".equals(s)) {
list.add("javaee");
// list.set(x, "javaee");// 用指定的元素替代此列表中指定位置上的元素。
}
}
System.out.println("list:" + list);
}
}

List的子类特点

  ArrayList

    底层数据结构是数组,查询快,增删慢。

    线程不安全,效率高。

  Vector

    底层数据结构是数组,查询快,增删慢。

    线程安全,效率低。

  LinkedList

    底层数据结构是链表,查询慢,增删快。

    线程不安全,效率高。

  到底使用谁呢?看需求?

    分析:

      要安全吗?

        要:Vector(即使要,也不使用这个,后面再说)

        不要:ArrayList或者LinkedList

          查询多;ArrayList

          增删多:LinkedList

  什么都不知道,就用ArrayList。

List集合案例

遍历方式、迭代器、普通for

  A:存储字符串并遍历

  B:存储自定义对象并遍历

集合(List)的子类

List的子类特点

  ArrayList:

    线性数据结构(底层数据结构是数组)。查询快,增删慢。线程不安全,效率高。创建集合时可以指定集合的长度。

  Vector:

    线性数据结构(底层数据结构是数组)。查询快,增删慢。线程安全,效率低。功能与ArrayList完全一致。

  LinkedList:

    链表数据结构(底层数据结构是链表)。查询慢,增删快。线程不安全,效率高。创建集合时不能指定集合的长度。

案例:使用List的任何子类存储字符串或者存储自定义对象并遍历。

ArrayList

  A:没有特有功能需要学习

  B:案例

    a:ArrayList存储字符串并遍历

    b:ArrayList存储自定义对象并遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//ArrayList的使用:存储字符串并遍历
public class ArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList<String> array = new ArrayList<String>();

// 创建元素对象,并添加元素
array.add("hello");
array.add("world");
array.add("java");

// 遍历
Iterator<String> it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}

for (int x = 0; x < array.size(); x++) {
String s = (String) array.get(x);
System.out.println(s);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//ArrayList的使用:存储自定义对象并遍历
public class ArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList<Student> array = new ArrayList<Student>();

// 创建学生对象
Student s1 = new Student("武松", 30);
Student s2 = new Student("鲁智深", 40);
Student s3 = new Student("林冲", 36);
Student s4 = new Student("杨志", 38);

// 添加元素
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);

// 遍历
Iterator<Student> it = array.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());
}

for (int x = 0; x < array.size(); x++) {
Student s = (Student) array.get(x);
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

Vector

  A:有特有功能

1
2
3
4
5
6
7
8
    a:添加
      public void addElement(E obj):将指定元素添加到此向量的末尾。 -- public boolean add(E e)

    b:获取
      public E elementAt(int index):返回指定索引处的组件。 -- public E get(int index)
      public Enumeration<E> elements():返回此向量的组件的枚举。 -- iterator()
        boolean hasMoreElements():测试此枚举是否包含更多的元素。
        E nextElement():如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
Vector<String> v = new Vector<String>();

// 添加功能
v.addElement("hello");
v.addElement("world");
v.addElement("java");

// 遍历
for (int x = 0; x < v.size(); x++) {
String s = (String) v.elementAt(x);
System.out.println(s);
}

Enumeration<String> en = v.elements(); // 返回的是实现类的对象
while (en.hasMoreElements()) {
String s = (String) en.nextElement();
System.out.println(s);
}
}
}

  B:案例

    a:Vector存储字符串并遍历

    b:Vector存储自定义对象并遍历

LinkedList

  A:有特有功能

1
2
3
4
5
6
7
8
9
10
11
    a:添加
      public void addFirst(E e):将指定元素插入此列表的开头。
      public void addLast(E e):将指定元素添加到此列表的结尾。

    b:获取
      public E getFirst():返回此列表的第一个元素。
      public E getLast():返回此列表的最后一个元素。

    c:删除
      public E removeFirst():移除并返回此列表的第一个元素。
      public E removeLast():移除并返回此列表的最后一个元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class LinkedListDemo {
public static void main(String[] args) {
// 创建集合对象
LinkedList<String> link = new LinkedList<String>();

// 添加元素
link.add("hello");
link.add("world");
link.add("java");

// public void addFirst(Object e)
// link.addFirst("javaee");

// public void addLast(Object e)
// link.addLast("android");

// public Object getFirst()
// System.out.println("getFirst:" + link.getFirst());

// public Obejct getLast()
// System.out.println("getLast:" + link.getLast());

// public Object removeFirst()
System.out.println("removeFirst:" + link.removeFirst()); // removeFirst:hello

// public Object removeLast()
System.out.println("removeLast:" + link.removeLast()); // removeLast:java

// 输出对象名
System.out.println("link:" + link); // link:[world]
}
}

  B:案例

    a:LinkedList存储字符串并遍历

    b:LinkedList存储自定义对象并遍历

案例

  A: ArrayList去除集合中的多个字符串的重复元素(如果字符串的内容相同,即为重复元素)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
* ArrayList去除集合中字符串的重复值(字符串的内容相同)
* 分析:
* A:创建集合对象
* B:添加多个字符串元素(包含内容相同的)
* C:创建新集合
* D:遍历旧集合,获取得到每一个元素
* E:拿这个元素到新集合去找,看有没有
* 有:不搭理它
* 没有:就添加到新集合
* F:遍历新集合
*/
public class ArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList<String> array = new ArrayList<String>();

// 添加多个字符串元素(包含内容相同的)
array.add("hello");
array.add("world");
array.add("java");
array.add("world");
array.add("java");
array.add("world");
array.add("world");
array.add("world");
array.add("world");
array.add("java");
array.add("world");

// 创建新集合
ArrayList<String> newArray = new ArrayList<String>();
// 遍历旧集合,获取得到每一个元素
Iterator<String> it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
// 拿这个元素到新集合去找,看有没有
if (!newArray.contains(s)) {
newArray.add(s);
}
}

// 遍历新集合
for (int x = 0; x < newArray.size(); x++) {
String s = (String) newArray.get(x);
System.out.println(s);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*
* 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同)
* 要求:不能创建新的集合,就在以前的集合上做。
*/
public class ArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList<String> array = new ArrayList<String>();

// 添加多个字符串元素(包含内容相同的)
array.add("hello");
array.add("world");
array.add("java");
array.add("world");
array.add("java");
array.add("world");
array.add("world");
array.add("world");
array.add("world");
array.add("java");
array.add("world");

// 由选择排序思想引入,我们就可以通过这种思想做这个题目
// 拿0索引的依次和后面的比较,有就把后的干掉
// 同理,拿1索引...
for (int x = 0; x < array.size() - 1; x++) {
for (int y = x + 1; y < array.size(); y++) {
if (array.get(x).equals(array.get(y))) {
array.remove(y);
y--;
}
}
}

// 遍历集合
Iterator<String> it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}

  B: ArrayList去除集合中的自定义对象的重复元素(如果自定义对象的成员变量值都相同,即为重复元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
* 我们按照和字符串一样的操作,发现出问题了。
* 为什么呢?
* 我们必须思考哪里会出问题?
* 通过简单的分析,我们知道问题出现在了判断上。
* 而这个判断功能是集合自己提供的,所以我们如果想很清楚的知道它是如何判断的,就应该去看源码。
* contains()方法的底层依赖的是equals()方法。
* 而我们的学生类中没有equals()方法,这个时候,默认使用的是它父亲Object的equals()方法
* Object()的equals()默认比较的是地址值,所以,它们进去了。因为new的东西,地址值都不同。
* 按照我们自己的需求,比较成员变量的值,重写equals()即可。
* 自动生成即可。
*/
public class ArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList<Student> array = new ArrayList<Student>();

// 创建学生对象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("林志玲", 40);
Student s3 = new Student("凤姐", 35);
Student s4 = new Student("芙蓉姐姐", 18);
Student s5 = new Student("翠花", 16);
Student s6 = new Student("林青霞", 27);
Student s7 = new Student("林青霞", 18);

// 添加元素
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);
array.add(s6);
array.add(s7);

// 创建新集合
ArrayList<Student> newArray = new ArrayList<Student>();
// 遍历旧集合,获取得到每一个元素
Iterator<Student> it = array.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
// 拿这个元素到新集合去找,看有没有
if (!newArray.contains(s)) {
newArray.add(s);
}
}

// 遍历新集合
for (int x = 0; x < newArray.size(); x++) {
Student s = (Student) newArray.get(x);
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}

  C:用LinkedList模拟一个栈数据结构的集合类,并测试。

    你要定义一个集合类,只不过内部可以使用LinkedList来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// MyStackList的测试
public class MyStackListDemo {
public static void main(String[] args) {
// 创建集合对象
MyStackList msl = new MyStackList();

// 添加元素
msl.add("hello");
msl.add("world");
msl.add("java");
// System.out.println(msl.get());
// System.out.println(msl.get());
// System.out.println(msl.get());
// System.out.println(msl.get()); // NoSuchElementException
while (!msl.isEmpty()) {
System.out.println(msl.get());
}
}
}

// 自定义的栈集合类
class MyStackList {
private LinkedList<Object> link;

public MyStackList() {
link = new LinkedList<Object>();
}

public void add(Object obj) {
link.addFirst(obj);
}

public Object get() {
// return link.getFirst();
return link.removeFirst(); // return link.remove();效果是一样的
}

public boolean isEmpty() {
return link.isEmpty();
}
}

Generic泛型

泛型概述

  是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递。

格式

  <数据类型>

  注意:该数据类型只能是引用类型。

好处

  A:把运行时期的问题提前到了编译期间

  B:避免了强制类型转换

  C:优化了程序设计,解决了黄色警告线问题,让程序更安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
* ArrayList存储字符串并遍历
*
* 不使用泛型,写这个程序, 结果出错了。
* 为什么呢?
* 因为我们开始存储的时候,存储了String和Integer两种类型的数据。
* 而在遍历的时候,我们把它们都当作String类型处理的,做了转换,所以就报错了。
* 但是呢,它在编译期间却没有告诉我们。所以,我就觉得这个设计的不好。
* 回想一下,我们的数组
* String[] strArray = new String[3];
* strArray[0] = "hello";
* strArray[1] = "world";
* strArray[2] = 10;// 编译出错
* 集合也模仿着数组的这种做法,在创建对象的时候明确元素的数据类型。这样就不会在有问题了。
* 而这种技术被称为:泛型。
*/
public class GenericDemo {
public static void main(String[] args) {
// 创建
ArrayList<String> array = new ArrayList<String>();

// 添加元素
array.add("hello");
array.add("world");
array.add("java");
// array.add(new Integer(100)); // 定义泛型前,编译没有问题
// array.add(10); // JDK5以后的自动装箱,等价于:array.add(Integer.valueOf(10));

// 遍历
Iterator<String> it = array.iterator();
while (it.hasNext()) {
// String s = (String) it.next(); // 定义泛型前:ClassCastException
String s = it.next(); // 定义泛型后就不用向下转型了
System.out.println(s);
}

// 看下面这个代码
// String[] strArray = new String[3];
// strArray[0] = "hello";
// strArray[1] = "world";
// strArray[2] = 10; // 编译出错
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 用ArrayList存储字符串元素,并遍历。用泛型改进代码
*/
public class GenericDemo {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<String>();

array.add("hello");
array.add("world");
array.add("java");

Iterator<String> it = array.iterator();
while (it.hasNext()) {
String s = it.next(); // 避免了向下转型
System.out.println(s);
}

for (int x = 0; x < array.size(); x++) {
String s = array.get(x); // 避免了向下转型
System.out.println(s);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
* 需求:存储自定义对象并遍历。
* A:创建学生类
* B:创建集合对象
* C:创建元素对象
* D:把元素添加到集合
* E:遍历集合
*/
public class GenericDemo {
public static void main(String[] args) {
// 创建集合对象
// ArrayList<Student> array = new ArrayList<>();// JDK7的新特性:泛型推断。但是不建议这样使用。
ArrayList<Student> array = new ArrayList<Student>();

// 创建元素对象
Student s1 = new Student("曹操", 40); // 后知后觉
Student s2 = new Student("蒋干", 30); // 不知不觉
Student s3 = new Student("诸葛亮", 26);// 先知先觉

// 添加元素
array.add(s1);
array.add(s2);
array.add(s3);

// 遍历
Iterator<Student> it = array.iterator();
while (it.hasNext()) {
Student s = it.next();
System.out.println(s.getName() + "---" + s.getAge());
}

for (int x = 0; x < array.size(); x++) {
Student s = array.get(x);
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

泛型的前世今生

  A:泛型的由来

    早期的时候,我们使用Object来代表任意的类型。

    向上转型是没有任何问题的,但是在向下转型的时候其实隐含了类型转换的问题。

    也就是说这样的程序其实并不是安全的。所以Java在JDK5后引入了泛型,提高程序的安全性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool ot = new ObjectTool();

ot.setObj(new Integer(27));
Integer i = (Integer) ot.getObj();// 正常使用
System.out.println("年龄是:" + i);

ot.setObj(new String("林青霞"));
String s = (String) ot.getObj();// 正常使用
System.out.println("姓名是:" + s);

ot.setObj(new Integer(30));
String ss = (String) ot.getObj();// ClassCastException
System.out.println("姓名是:" + ss);
}
}

class ObjectTool {
private Object obj;

public Object getObj() {
return obj;
}

public void setObj(Object obj) { // Object obj = new Integer(30);
this.obj = obj;
}
}

  B:泛型类:把泛型定义在类上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* 泛型类的测试
*/
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool<String> ot = new ObjectTool<String>();
// ot.setObj(new Integer(27)); // 这个时候编译期间就过不去
ot.setObj(new String("林青霞"));
String s = ot.getObj();
System.out.println("姓名是:" + s);

ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
// ot2.setObj(new String("风清扬")); // 这个时候编译期间就过不去
ot2.setObj(new Integer(27));
Integer i = ot2.getObj();
System.out.println("年龄是:" + i);
}
}

/**
* 泛型类:把泛型定义在类上
*/
class ObjectTool<T> {
private T obj;

public T getObj() {
return obj;
}

public void setObj(T obj) {
this.obj = obj;
}
}

  C:泛型方法:把泛型定义在方法上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class ObjectToolDemo {
public static void main(String[] args) {
ObjectTool ot = new ObjectTool();
ot.show("hello");
ot.show(100);
ot.show(true);

ObjectTool<String> ot1 = new ObjectTool<String>();
ot1.show("hello");

ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
ot2.show(100);

ObjectTool<Boolean> ot3 = new ObjectTool<Boolean>();
ot3.show(true);

// 但是呢,谁说了我的方法一定要和类的类型的一致呢?
// 我要是类上没有泛型的话,方法还能不能接收任意类型的参数了呢?

// 定义泛型方法后
ObjectTool2 ot4 = new ObjectTool2();
ot4.show("hello");
ot4.show(100);
ot4.show(true);
}
}

class ObjectTool<T> {
// public void show(String s) {
// System.out.println(s);
// }
//
// public void show(Integer i) {
// System.out.println(i);
// }
//
// public void show(Boolean b) {
// System.out.println(b);
// }

public void show(T t) {
System.out.println(t);
}
}

// 泛型方法:把泛型定义在方法上
class ObjectTool2 {
public <T> void show(T t) {
System.out.println(t);
}
}

  D:泛型接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 泛型接口:把泛型定义在接口上
interface Inter<T> {
public abstract void show(T t);
}

// 实现类在实现泛型接口的时候,也需要定义泛型
class InterImpl<T> implements Inter<T> {
public void show(T t) {
System.out.println(t);
}
}

public class InterDemo {
public static void main(String[] args) {
Inter<String> i = new InterImpl<String>();
i.show("hello");

Inter<Integer> ii = new InterImpl<Integer>();
ii.show(100);
}
}

  E:泛型高级(通配符)

    ?       :任意类型,如果没有明确,那么就是Object以及任意的Java类了

    ? extends E   :上边界(上界),向下限定,E及其子类

    ? super E   :下边界(下界),向上限定,E极其父类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class GenericDemo {
public static void main(String[] args) {
// 泛型如果明确的写的时候,前后必须一致
Collection<Object> c1 = new ArrayList<Object>();
// Collection<Object> c2 = new ArrayList<Animal>(); // 错误形式
// Collection<Object> c3 = new ArrayList<Dog>(); // 错误形式
// Collection<Object> c4 = new ArrayList<Cat>(); // 错误形式

// ?表示任意的类型都是可以的
Collection<?> c5 = new ArrayList<Object>();
Collection<?> c6 = new ArrayList<Animal>();
Collection<?> c7 = new ArrayList<Dog>();
Collection<?> c8 = new ArrayList<Cat>();

// ? extends E:上边界(上界),向下限定,E及其子类
// Collection<? extends Animal> c9 = new ArrayList<Object>(); // 错误形式
Collection<? extends Animal> c10 = new ArrayList<Animal>();
Collection<? extends Animal> c11 = new ArrayList<Dog>();
Collection<? extends Animal> c12 = new ArrayList<Cat>();

// ? super E:下边界(下界),向上限定,E极其父类
Collection<? super Animal> c13 = new ArrayList<Object>();
Collection<? super Animal> c14 = new ArrayList<Animal>();
// Collection<? super Animal> c15 = new ArrayList<Dog>(); // 错误形式
// Collection<? super Animal> c16 = new ArrayList<Cat>(); // 错误形式
}
}

class Animal {
}

class Dog extends Animal {
}

class Cat extends Animal {
}

应用

  看API,如果类,接口,抽象类后面跟的有<E>就说明要使用泛型。一般来说就是在集合中使用。

JDK5News

JDK5的新特性:自动拆装箱,泛型,增强for,静态导入,可变参数,枚举

一、增强for循环(掌握)

  1. 是for循环的一种

  2. 格式:

    for(元素的数据类型 变量名 : 数组或者Collection集合的对象) {

      使用该变量即可,该变量其实就是数组或者集合中的元素。

    }

  3. 好处:

    简化了数组和集合的遍历

  4. 弊端

    增强for循环的目标不能为null。建议在使用前,先判断是否为null。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class ForDemo {
public static void main(String[] args) {
// 定义一个int数组
int[] arr = { 1, 2, 3, 4, 5 };
// 普通for
for (int x = 0; x < arr.length; x++) {
System.out.println(arr[x]);
}

// 增强for
for (int x : arr) {
System.out.println(x);
}

// 定义一个字符串数组
String[] strArray = { "林青霞", "风清扬", "东方不败", "刘意" };
// 增强for
for (String s : strArray) {
System.out.println(s);
}

// 定义一个集合
ArrayList<String> array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
// 增强for
for (String s : array) {
System.out.println(s);
}

// List<String> list = null;
// if (list != null) {
// for (String s : list) {
// System.out.println(s);
// }
// }
// NullPointerException
// 这个s是我们从list里面获取出来的,在获取前,它肯定还要做一个判断
// 说白了,这就是迭代器的功能

// 增强for其实是用来替代迭代器的
// ConcurrentModificationException 详情参考: Java_集合04_集合(List)
// for (String s : array) {
// if ("world".equals(s)) {
// array.add("javaee");
// }
// }
// System.out.println("array:" + array);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*
* ArrayList存储字符串并遍历。要求加入泛型,并用增强for遍历。
* A:迭代器
* B:普通for
* C:增强for
*/
public class ArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList<String> array = new ArrayList<String>();

// 创建并添加元素
array.add("hello");
array.add("world");
array.add("java");

// 遍历集合
// 迭代器
Iterator<String> it = array.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}

// 普通for
for (int x = 0; x < array.size(); x++) {
String s = array.get(x);
System.out.println(s);
}

// 增强for
for (String s : array) {
System.out.println(s);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
* 需求:ArrayList存储自定义对象并遍历。要求加入泛型,并用增强for遍历。
* A:迭代器
* B:普通for
* C:增强for
*
* LinkedList,Vector,Colleciton,List等存储自己练习。
*
* 增强for是用来替迭代器。
*/
public class ArrayListDemo2 {
public static void main(String[] args) {
// 创建集合对象
ArrayList<Student> array = new ArrayList<Student>();

// 创建学生对象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("貂蝉", 22);
Student s3 = new Student("杨玉环", 24);
Student s4 = new Student("西施", 21);
Student s5 = new Student("王昭君", 23);

// 把学生对象添加到集合中
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);

// 迭代器
Iterator<Student> it = array.iterator();
while (it.hasNext()) {
Student s = it.next();
System.out.println(s.getName() + "---" + s.getAge());
}

// 普通for
for (int x = 0; x < array.size(); x++) {
Student s = array.get(x);
System.out.println(s.getName() + "---" + s.getAge());
}

// 增强for
for (Student s : array) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class Student {
private String name;
private int age;

public Student() {
super();
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

二、静态导入(了解)

  1. 可以导入到方法级别的导入

  2. 格式:

    import static 包名….类名.方法名;

  3. 注意事项:

    A:方法必须是静态的

    B:如果多个类下有同名的静态方法,就不好区分了,必须加前缀。所以一般我们并不使用静态导入,但是一定要能够看懂。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import static java.lang.Math.max;
import static java.lang.Math.pow;

// 错误
// import static java.util.ArrayList.add;

public class StaticImportDemo {
public static void main(String[] args) {
System.out.println(java.lang.Math.abs(-100));
System.out.println(java.lang.Math.pow(2, 3));
System.out.println(java.lang.Math.max(20, 30));
// 太复杂,我们就引入到import

System.out.println(Math.abs(-100));
System.out.println(Math.pow(2, 3));
System.out.println(Math.max(20, 30));
// 太复杂,有更简单

// System.out.println(abs(-100));// 需加前缀
System.out.println(java.lang.Math.abs(-100));
System.out.println(pow(2, 3));
System.out.println(max(20, 30));
}

public static void abs(String s) {
System.out.println(s);
}
}

三、可变参数(掌握)

  1. 如果我们在写方法的时候,参数个数不明确,就应该定义可变参数。

  2. 格式:

      修饰符 返回值类型 方法名(数据类型… 变量名) {}

    注意:

      A:该变量名其实是一个数组名

      B:如果一个方法有多个参数,并且有可变参数,可变参数必须在最后

  3. Arrays工具类的一个方法

      asList() : 把数组转成集合

      注意:这个集合的长度不能改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 需求:我要写一个求和的功能,到底是几个数据求和呢,我不太清楚,但是我知道在调用的时候我肯定就知道了
* 为了解决这个问题,Java就提供了一个东西:可变参数
*/
public class ArgsDemo {
public static void main(String[] args) {
int result = sum(10, 20, 30, 40);
System.out.println("result:" + result); // result:100

result = sum(10, 20, 30, 40, 50);
System.out.println("result:" + result); // result:150
}

public static int sum(int b, int... a) {
System.out.println(a); // [I@15db9742 由此可见,这里的 a 是数组名。
int s = b;
for (int x : a) {
s += x;
}
return s;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
* public static <T> List<T> asList(T... a):把数组转成集合
*
* 注意事项:
* 虽然可以把数组转成集合,但是集合的长度不能改变。
*/
public class ArraysDemo {
public static void main(String[] args) {
// 定义一个数组
// String[] strArray = { "hello", "world", "java" };
// List<String> list = Arrays.asList(strArray);
List<String> list = Arrays.asList("hello", "world", "java");

// list.add("javaee"); // UnsupportedOperationException
// list.remove(1); // UnsupportedOperationException

list.set(1, "javaee");

for (String s : list) {
System.out.println(s); // hello \n javaee \n java \n
}
}
}

List_Son_test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
* 集合的嵌套遍历
* 需求:
* 我们班有学生,每一个学生是一个对象。所以我们可以使用一个集合表示我们班级的学生。ArrayList<Student>
* 但是呢,我们旁边是不是还有班级,每个班级是不是也是一个ArrayList<Student>。
* 而我现在有多个ArrayList<Student>。也要用集合存储,怎么办呢?
* 就是这个样子的:ArrayList<ArrayList<Student>>
*/
public class ArrayListDemo {
public static void main(String[] args) {
// 创建大集合
ArrayList<ArrayList<Student>> bigArrayList = new ArrayList<ArrayList<Student>>();

// 创建第一个班级的学生集合
ArrayList<Student> firstArrayList = new ArrayList<Student>();
// 创建学生
Student s1 = new Student("唐僧", 30);
Student s2 = new Student("孙悟空", 29);
Student s3 = new Student("猪八戒", 28);
Student s4 = new Student("沙僧", 27);
Student s5 = new Student("白龙马", 26);
// 学生进班
firstArrayList.add(s1);
firstArrayList.add(s2);
firstArrayList.add(s3);
firstArrayList.add(s4);
firstArrayList.add(s5);
// 把第一个班级存储到学生系统中
bigArrayList.add(firstArrayList);

// 创建第二个班级的学生集合
ArrayList<Student> secondArrayList = new ArrayList<Student>();
// 创建学生
Student s11 = new Student("诸葛亮", 30);
Student s22 = new Student("司马懿", 28);
Student s33 = new Student("周瑜", 26);
// 学生进班
secondArrayList.add(s11);
secondArrayList.add(s22);
secondArrayList.add(s33);
// 把第二个班级存储到学生系统中
bigArrayList.add(secondArrayList);

// 创建第三个班级的学生集合
ArrayList<Student> thirdArrayList = new ArrayList<Student>();
// 创建学生
Student s111 = new Student("宋江", 40);
Student s222 = new Student("吴用", 35);
Student s333 = new Student("高俅", 30);
Student s444 = new Student("李师师", 22);
// 学生进班
thirdArrayList.add(s111);
thirdArrayList.add(s222);
thirdArrayList.add(s333);
thirdArrayList.add(s444);
// 把第三个班级存储到学生系统中
bigArrayList.add(thirdArrayList);

// 遍历集合
for (ArrayList<Student> array : bigArrayList) {
for (Student s : array) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
}

class Student {
private String name;
private int age;

public Student() {
super();
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
* 获取10个1-20之间的随机数,要求不能重复
*
* 用数组实现,但是数组的长度是固定的,长度不好确定。
* 所以我们使用集合实现。
*
* 分析:
* A:创建产生随机数的对象
* B:创建一个存储随机数的集合。
* C:定义一个统计变量。从0开始。
* D:判断统计遍历是否小于10
* 是:先产生一个随机数,判断该随机数在集合中是否存在。
* 如果不存在:就添加,统计变量++。
* 如果存在:就不搭理它。
* 否:不搭理它
* E:遍历集合
*/
public class RandomDemo {
public static void main(String[] args) {
// 创建产生随机数的对象
Random r = new Random();

// 创建一个存储随机数的集合。
ArrayList<Integer> array = new ArrayList<Integer>();

// 定义一个统计变量。从0开始。
int count = 0;

// 判断统计遍历是否小于10
while (count < 10) {
// 先产生一个随机数
int number = r.nextInt(20) + 1;

// 判断该随机数在集合中是否存在。
if (!array.contains(number)) {
// 如果不存在:就添加,统计变量++。
array.add(number);
count++;
}
}

// 遍历集合
for (Integer i : array) {
System.out.println(i);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*
* 键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值
*
* 分析:
* A:创建键盘录入数据对象
* B:键盘录入多个数据,我们不知道多少个,所以用集合存储
* C:以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
* D:把集合转成数组
* E:对数组排序
* F:获取该数组中的最大索引的值
*/
public class ArrayListDemo {
public static void main(String[] args) {
// 创建键盘录入数据对象
Scanner sc = new Scanner(System.in);

// 键盘录入多个数据,我们不知道多少个,所以用集合存储
ArrayList<Integer> array = new ArrayList<Integer>();

// 以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
while (true) {
System.out.println("请输入数据:");
int number = sc.nextInt();
if (number != 0) {
array.add(number);
} else {
break;
}
}

// 把集合转成数组
// public <T> T[] toArray(T[] a):按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;
// 返回数组的运行时类型是指定数组的运行时类型。
// 如果指定的数组能容纳列表,则将该列表返回此处。
// 否则,将分配一个具有指定数组的运行时类型和此列表大小的新数组。
Integer[] i = new Integer[array.size()];

// Integer[] ii = array.toArray(i);
array.toArray(i);

// System.out.println(i);
// System.out.println(ii);输出 i 和 ii 的地址值相同

// 对数组排序
// public static void sort(Object[] a)
Arrays.sort(i);

// 获取该数组中的最大索引的值
System.out.println("数组是:" + arrayToString(i) + "最大值是:" + i[i.length - 1]);
}

public static String arrayToString(Integer[] i) {
StringBuilder sb = new StringBuilder();

sb.append("[");
for (int x = 0; x < i.length; x++) {
if (x == i.length - 1) {
sb.append(i[x]);
} else {
sb.append(i[x]).append(", ");
}
}
sb.append("]");

return sb.toString();
}
}

集合(Set)

Set集合特点

  Set:不保存元素加入的顺序(存储顺序和取出顺序不一定一致),不能保存重复值

    |– HashSet:底层数据结构是哈希表(是一个元素为链表的数组)。集合中的元素根据哈希值进行排序(好像不是)。创建集合时可以指定集合的长度,长度不够时默认以75%的比例增加长度。

    |– TreeSet类:底层数据结构是红黑树(是一个自平衡的二叉树)。集合中的元素按照某种规则进行排序。创建集合不能指定集合的长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SetDemo {
public static void main(String[] args) {
// 创建集合对象
Set<String> set = new HashSet<String>();

// 创建并添加元素
set.add("hello");
set.add("java");
set.add("world");
set.add("java");
set.add("world");

// 增强for
for (String s : set) {
System.out.println(s); // java \n world \n hello \n
}
}
}

HashSet集合

它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素

  A:底层数据结构是哈希表(是一个元素为链表的数组)

  B:哈希表底层依赖两个方法:hashCode()和equals()

    执行顺序:

      首先比较哈希值是否相同

        相同:继续执行equals()方法

          返回true:元素重复了,不添加

          返回false:直接把元素添加到集合

        不同:就直接把元素添加到集合

  C:如何保证元素唯一性的呢?

    由hashCode()和equals()保证的

  D:开发的时候,代码非常的简单,自动生成即可。

  E:HashSet存储字符串并遍历

  F:HashSet存储自定义对象并遍历(对象的成员变量值相同即为同一个元素)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
* HashSet:存储字符串并遍历
* 问题:为什么存储字符串的时候,字符串内容相同的只存储了一个呢?
* 通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()。
* 步骤:
* 首先比较哈希值
* 如果相同,继续走,比较地址值或者走equals()
* 如果不同,就直接添加到集合中
* 按照方法的步骤来说:
* 先看hashCode()值是否相同
* 相同:继续走equals()方法
* 返回true: 说明元素重复,就不添加
* 返回false:说明元素不重复,就添加到集合
* 不同:就直接把元素添加到集合
* 如果类没有重写这两个方法,默认使用的Object()。一般来说不会相同。
* 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。
*/
public class HashSetDemo {
public static void main(String[] args) {
// 创建集合对象
HashSet<String> hs = new HashSet<String>();

// 创建并添加元素
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");

// 遍历集合
for (String s : hs) {
System.out.println(s);// world \n java \n hello \n
}

HashCodeDemo.test();
}
}

class HashCodeDemo {
public static void test() {
System.out.println("hello".hashCode());// 99162322
System.out.println("hello".hashCode());// 99162322
System.out.println("world".hashCode());// 113318802
}
}

HashSet集合的add()方法的源码解析:(JDK版本不同,源码可能会不同)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
interface Collection {
...
}

interface Set extends Collection {
...
}

class HashSet implements Set {
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;

public HashSet() {
map = new HashMap<>();
}

public boolean add(E e) { //e=hello,world
return map.put(e, PRESENT)==null;
}
}

class HashMap implements Map {
public V put(K key, V value) { //key=e=hello,world

//看哈希表是否为空,如果空,就开辟空间
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}

//判断对象是否为null
if (key == null)
return putForNullKey(value);

int hash = hash(key); //和对象的hashCode()方法相关

//在哈希表中查找hash值
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
//这次的e其实是第一次的world
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
//走这里其实是没有添加元素
}
}

modCount++;
addEntry(hash, key, value, i); //把元素添加
return null;
}

transient int hashSeed = 0;

final int hash(Object k) { //k=key=e=hello,
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}

h ^= k.hashCode(); //这里调用的是对象的hashCode()方法

// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
}


hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
* 需求:存储自定义对象,并保证元素的唯一性
* 要求:如果两个对象的成员变量值都相同,则为同一个元素。
*
* 目前是不符合我的要求的:因为我们知道HashSet底层依赖的是hashCode()和equals()方法。
* 而这两个方法我们在学生类中没有重写,所以,默认使用的是Object类。
* 这个时候,他们的哈希值是不会一样的,根本就不会继续判断,执行了添加操作。
*/
public class HashSetDemo2 {
public static void main(String[] args) {
// 创建集合对象
HashSet<Student> hs = new HashSet<Student>();

// 创建学生对象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("柳岩", 22);
Student s3 = new Student("王祖贤", 30);
Student s4 = new Student("林青霞", 27);
Student s5 = new Student("林青霞", 20);
Student s6 = new Student("范冰冰", 22);

// 添加元素
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
hs.add(s5);
hs.add(s6);

// 遍历集合
for (Student s : hs) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}

/*@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}*/
}

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
* LinkedHashSet:底层数据结构由哈希表和链表组成。
* 哈希表保证元素的唯一性。
* 链表保证元素有序。(存储和取出是一致)
*/
public class LinkedHashSetDemo {
public static void main(String[] args) {
// 创建集合对象
LinkedHashSet<String> hs = new LinkedHashSet<String>();

// 创建并添加元素
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
hs.add("java");

// 遍历
for (String s : hs) {
System.out.println(s);// hello \n world \n java \n
}
}
}

TreeSet集合

使用元素的自然顺序对元素进行排序,或者根据创建集合时提供的 Comparator 进行排序,具体取决于使用的构造方法(详情看API:TreeSet的构造方法)。总之,元素或集合必须要有比较性

  A:底层数据结构是红黑树(是一个自平衡的二叉树)

  B:保证元素的排序方式

    a:自然排序(元素具备比较性)

      存储的元素所属的类实现自然排序接口:Comparable接口

    b:比较器排序(集合具备比较性)

      让集合构造方法接收Comparator的实现类对象

  C:把代码看一遍即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class TreeSetDemo {
public static void main(String[] args) {
// 创建集合对象
// 自然顺序进行排序
TreeSet<Integer> ts = new TreeSet<Integer>(); // 存储的元素所属的类Integer以实现了Comparable<Integer>接口

// 创建元素并添加
// 20,18,23,22,17,24,19,18,24
ts.add(20);
ts.add(18);
ts.add(23);
ts.add(22);
ts.add(17);
ts.add(24);
ts.add(19);
ts.add(18);
ts.add(24);

// 遍历
for (Integer i : ts) {
System.out.println(i);
}
}
}

TreeSet的add()方法的源码解析:(JDK版本不同,源码可能会不同)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
interface Collection {...}

interface Set extends Collection {...}

interface NavigableMap {

}

class TreeMap implements NavigableMap {
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check

root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
}

class TreeSet implements Set {
private transient NavigableMap<E,Object> m;

public TreeSet() {
this(new TreeMap<E,Object>());
}

public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
}

真正的比较是依赖于元素的compareTo()方法,而这个方法是定义在 Comparable里面的。
所以,你要想重写该方法,就必须实现 Comparable接口。这个接口表示的就是自然排序。

TreeSet存储元素自然排序和唯一(元素不重复)的图解:

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
* TreeSet存储自定义对象并保证排序和唯一。
* 要求:自然排序,按照年龄从小到大排序
* 成员变量值都相同即为同一个元素
* 如果Student不实现Comparable接口就会抛出以下异常
* java.lang.ClassCastException: cn.cast.Student cannot be cast to java.lang.Comparable
*/
public class TreeSetDemo2 {
public static void main(String[] args) {
// 创建集合对象
TreeSet<Student> ts = new TreeSet<Student>();

// 创建元素
Student s1 = new Student("l__", 27);
Student s2 = new Student("z__", 29);
Student s3 = new Student("w__", 23);
Student s4 = new Student("l__", 27); // 此为重复数据
Student s5 = new Student("l__", 22);
Student s6 = new Student("w__", 40);
Student s7 = new Student("f__", 22);
Student s8 = new Student("G__", 22);

// 添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
ts.add(s8);

// 遍历
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

/*
* 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口存储的元素所属的类
*/
class Student implements Comparable<Student> {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public int compareTo(Student s) {
// return 0;// 由源码可知,返回0说明元素相同,后面的元素不会被添加,所以只添加第一个。
// return 1;// 由源码可知,返回1说明新添加的元素是最大的,所以放在树的最右边,按添加顺序输出。
// return -1;// 由源码可知,返回-1说明新添加的元素是最小的,所以放在树的最左边,按添加倒序输出。

// 这里返回什么,其实应该根据我的排序规则来做
// 按照年龄排序,主要条件
int num = this.age - s.age;
// return num;// 如果年龄相同,就会返回0,并没有判断姓名。不符合要求。

// 次要条件
// 年龄相同的时候,还得去看姓名是否也相同。如果年龄和姓名都相同,才是同一个元素
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
// String类实现了Comparable接口,按字典顺序比较两个字符
return num2;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
* 需求:请按照姓名的长度排序
*/
public class TreeSetDemo {
public static void main(String[] args) {
// 创建集合对象
TreeSet<Student> ts = new TreeSet<Student>();

// 创建元素
Student s1 = new Student("l", 27);
Student s2 = new Student("zhang", 29);
Student s3 = new Student("wangl", 23);
Student s4 = new Student("linqing", 29);
Student s5 = new Student("linqing", 22);
Student s6 = new Student("liu", 22);
Student s7 = new Student("wuqilong", 40);
Student s8 = new Student("linqingxia", 29);

// 添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
ts.add(s8);

// 遍历
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

/*
* 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口
*/
class Student implements Comparable<Student> {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public int compareTo(Student s) {
// 主要条件 姓名的长度
int num = this.name.length() - s.name.length();
// 姓名的长度相同,不代表姓名的内容相同
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
// 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄
int num3 = num2 == 0 ? this.age - s.age : num2;
return num3;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

如果很多地方使用Student类,要求的排序方式又不同,那就没办法实现了。这时就需要使用比较器排序,看下面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
* 需求:请按照姓名的长度排序
*
* TreeSet集合保证元素排序和唯一性的原理
* 唯一性:是根据比较的返回是否是0来决定。
* 排序:
* A:自然排序(元素具备比较性)
* 让存储的元素所属的类实现自然排序接口 Comparable
* B:比较器排序(集合具备比较性)
* 让集合的构造方法接收一个比较器接口(Comparator)的子类对象
*/
public class TreeSetDemo {
public static void main(String[] args) {
// 创建集合对象
// TreeSet<Student> ts = new TreeSet<Student>(); // 自然排序
// public TreeSet(Comparator<? super E> comparator) // 比较器排序

// 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象
// 而匿名内部类就可以实现这个东西,没必要单独写一个类,而且那样灵活度也不高。
// 而且比较器排序的匿名内部类实现,要比上面(自然排序)例子Student类实现Comparable接口要好,因为如果很多地方使用Student类,要求的排序方式又不同,那就没办法实现了。该种方式灵活度更高。
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 姓名长度
int num = s1.getName().length() - s2.getName().length();
// 姓名内容
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
// 年龄
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
});
// TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());

// 创建元素
Student s1 = new Student("l", 27);
Student s2 = new Student("zhang", 29);
Student s3 = new Student("wangl", 23);
Student s4 = new Student("linqing", 29);
Student s5 = new Student("linqing", 22);
Student s6 = new Student("liu", 22);
Student s7 = new Student("wuqilong", 40);
Student s8 = new Student("linqingxia", 29);

// 添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
ts.add(s8);

// 遍历
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class MyComparator implements Comparator<Student> {
public int compare(Student s1, Student s2) {
// int num = this.name.length() - s.name.length();
// this -- s1
// s -- s2
// 姓名长度
int num = s1.getName().length() - s2.getName().length();
// 姓名内容
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
// 年龄
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

案例

​ A:获取无重复的随机数

​ B:键盘录入学生按照总分从高到底输出

案例A:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
* 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
*
* 分析:
* A:创建随机数对象
* B:创建一个HashSet集合
* C:判断集合的长度是不是小于10
* 是:就创建一个随机数添加
* 否:不搭理它
* D:遍历HashSet集合
*/
public class HashSetDemo {
public static void main(String[] args) {
// 创建随机数对象
Random r = new Random();

// 创建一个Set集合
HashSet<Integer> ts = new HashSet<Integer>();

// 判断集合的长度是不是小于10
while (ts.size() < 10) {
int num = r.nextInt(20) + 1;
ts.add(num);
}

// 遍历Set集合
for (Integer i : ts) {
System.out.println(i);
}
System.out.println(ts);
}
}

案例B:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
* 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
*
* 分析:
* A:定义学生类
* B:创建一个TreeSet集合
* C:总分从高到底如何实现呢?
* D:键盘录入5个学生信息
* E:遍历TreeSet集合
*/
public class TreeSetDemo {
public static void main(String[] args) {
// 创建一个TreeSet集合
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 总分从高到低
int num = s2.getSum() - s1.getSum();
// 总分相同的不一定语文相同
int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
// 总分相同的不一定数序相同
int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
// 总分相同的不一定英语相同
int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;
// 姓名还不一定相同呢
int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName()) : num4;
return num5;
}
});

System.out.println("学生信息录入开始");
// 键盘录入5个学生信息
for (int x = 1; x <= 5; x++) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入第" + x + "个学生的姓名:");
String name = sc.nextLine();
System.out.println("请输入第" + x + "个学生的语文成绩:");
String chineseString = sc.nextLine();
System.out.println("请输入第" + x + "个学生的数学成绩:");
String mathString = sc.nextLine();
System.out.println("请输入第" + x + "个学生的英语成绩:");
String englishString = sc.nextLine();

// 把数据封装到学生对象中
Student s = new Student();
s.setName(name);
s.setChinese(Integer.parseInt(chineseString));
s.setMath(Integer.parseInt(mathString));
s.setEnglish(Integer.parseInt(englishString));

// 把学生对象添加到集合
ts.add(s);
}
System.out.println("学生信息录入完毕");

System.out.println("学习信息从高到低排序如下:");
System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩\t总分");
// 遍历集合
for (Student s : ts) {
System.out.println(s.getName() + "\t" + s.getChinese() + "\t" + s.getMath() + "\t" + s.getEnglish() + "\t" + (s.getChinese() + s.getMath() + s.getEnglish()));
}
}
}

class Student {
private String name;// 姓名
private int chinese;// 语文成绩
private int math;// 数学成绩
private int english;// 英语成绩

public Student() {
}

public Student(String name, int chinese, int math, int english) {
super();
this.name = name;
this.chinese = chinese;
this.math = math;
this.english = english;
}

public int getSum() {
return chinese + math + english;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getEnglish() {
return english;
}
public void setEnglish(int english) {
this.english = english;
}
}

集合(Map)

介绍

​ 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

Map和Collection的区别

  A:Map 存储的是键值对形式的元素,键唯一,值可以重复。

  B:Collection 存储的是单独出现的元素,子接口Set元素唯一,子接口List元素可重复。

Map接口功能概述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  A:添加功能
    V put(K key, V value):将指定的值与此映射中的指定键关联(可选操作)。返回:以前与 key 关联的值。如果没有针对 key 的映射关系,则返回 null
              (如果该实现支持 null 值,则返回 null 也可能表示此映射以前将 null 与 key 关联)。
    void putAll(Map<? extends K,? extends V> m):从指定映射中将所有映射关系复制到此映射中(可选操作)。

  B:删除功能
    void clear():从此映射中移除所有映射关系(可选操作)。此调用返回后,该映射将为空。
    V remove(Object key):如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。返回:以前与 key 关联的值;如果没有 key 的映射关系,则返回 null

  C:判断功能
    boolean containsKey(Object key):如果此映射包含指定键的映射关系,则返回 true
    boolean containsValue(Object value):如果此映射将一个或多个键映射到指定值,则返回 true
    boolean isEmpty():如果此映射未包含键-值映射关系,则返回 true

  D:获取功能
    Set<Map.Entry<K,V>> entrySet():返回此映射中包含的映射关系的 Set 视图。
    V get(Object key):返回指定键所映射的值;
    Set<K> keySet():返回此映射中包含的键的 Set 视图。
    Collection<V> values():返回此映射中包含的值的 Collection 视图。

  E:长度功能
    int size():返回此映射中的键-值映射关系数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class MapDemo {
public static void main(String[] args) {
// 创建集合对象
Map<String, String> map = new HashMap<String, String>();

// 添加元素
// V put(K key,V value):添加元素。
// System.out.println("put:" + map.put("文章", "马伊俐"));// put:null
// System.out.println("put:" + map.put("文章", "姚笛"));// put:马伊俐

map.put("邓超", "孙俪");
map.put("黄晓明", "杨颖");
map.put("周杰伦", "蔡依林");
map.put("刘恺威", "杨幂");

// void clear():移除所有的键值对元素
// map.clear();

// V remove(Object key):根据键删除键值对元素,并把值返回
// System.out.println("remove:" + map.remove("黄晓明"));// remove:杨颖
// System.out.println("remove:" + map.remove("黄海波"));// remove:null

// boolean containsKey(Object key):判断集合是否包含指定的键
System.out.println("containsKey:" + map.containsKey("黄晓明"));// containsKey:true
System.out.println("containsKey:" + map.containsKey("黄晓波"));// containsKey:false

// boolean isEmpty():判断集合是否为空
System.out.println("isEmpty:" + map.isEmpty());// isEmpty:false

// int size():返回集合中的键值对的对数
System.out.println("size:" + map.size());// size:4

// 输出集合名称
System.out.println("map:" + map);// map:{邓超=孙俪, 周杰伦=蔡依林, 黄晓明=杨颖, 刘恺威=杨幂}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
* 获取功能:
* V get(Object key):根据键获取值
* Set<K> keySet():获取集合中所有键的集合
* Collection<V> values():获取集合中所有值的集合
*/
public class MapDemo2 {
public static void main(String[] args) {
// 创建集合对象
Map<String, String> map = new HashMap<String, String>();

// 创建元素并添加元素
map.put("邓超", "孙俪");
map.put("黄晓明", "杨颖");
map.put("周杰伦", "蔡依林");
map.put("刘恺威", "杨幂");

// V get(Object key):根据键获取值
System.out.println("get:" + map.get("周杰伦"));// get:蔡依林
System.out.println("get:" + map.get("周杰"));// get:null

// Set<K> keySet():获取集合中所有键的集合
Set<String> set = map.keySet();
for (String key : set) {
System.out.println(key);// 邓超 \n 周杰伦 \n 黄晓明 \n 刘恺威 \n
}

// Collection<V> values():获取集合中所有值的集合
Collection<String> con = map.values();
for (String value : con) {
System.out.println(value);// 孙俪 \n 蔡依林 \n 杨颖 \n 杨幂 \n
}
}
}

Map集合遍历

  A:键找值

    a:获取所有键的集合

    b:遍历键的集合,获取每一个键

    c:根据键到集合中去找值

  B:键值对对象找键和值

    a:获取所有的键值对对象的集合

    b:遍历键值对对象的集合,获取每一个键值对对象

    c:根据键值对对象去获取键和值

  代码体现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Map<String,String> hm = new HashMap<String,String>();

hm.put("杨过", "小龙女");
hm.put("郭靖", "黄蓉");
hm.put("杨康", "穆念慈");
hm.put("陈玄风", "梅超风");

//方式1 键找值
Set<String> set = hm.keySet();
for(String key : set) {
String value = hm.get(key);
System.out.println(key+"---"+value);
}

//方式2 键值对对象找键和值
Set<Map.Entry<String,String>> set2 = hm.entrySet();
for(Map.Entry<String,String> me : set2) {
String key = me.getKey();
String value = me.getValue();
System.out.println(key+"---"+value);
}

HashMap集合练习

  A:HashMap<String,String>

  B:HashMap<Integer,String>

  C:HashMap<String,Student>

  D:HashMap<Student,String>

  E:LinkedHashMap<String,String> 保存元素加入的顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
* HashMap<String,String>
*/
public class HashMapDemo {
public static void main(String[] args) {
// 创建集合对象
HashMap<String, String> hm = new HashMap<String, String>();

// 创建元素并添加元素
hm.put("it001", "马云");
hm.put("it003", "马化腾");
hm.put("it004", "乔布斯");
hm.put("it005", "张朝阳");
hm.put("it002", "裘伯君");
hm.put("it001", "比尔盖茨");

// 遍历
Set<String> set = hm.keySet();
for (String key : set) {
String value = hm.get(key);
System.out.println(key + "---" + value);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
* HashMap<Integer,String>
*/
public class HashMapDemo2 {
public static void main(String[] args) {
// 创建集合对象
HashMap<Integer, String> hm = new HashMap<Integer, String>();

// 创建元素并添加元素
hm.put(27, "林青霞");
hm.put(30, "风清扬");
hm.put(29, "林青霞");
hm.put(28, "刘意");
hm.put(28, "刘意");
hm.put(28, "刘亦菲");

// 下面的写法是八进制,但是不能出现8以上的单个数据
// hm.put(003, "hello");
// hm.put(006, "hello");
// hm.put(007, "hello");
// hm.put(008, "hello");// 编译错误

// 遍历
Set<Integer> set = hm.keySet();
for (Integer key : set) {
String value = hm.get(key);
System.out.println(key + "---" + value);
}

// 下面这种方式仅仅是集合的元素的字符串表示
// System.out.println("hm:" + hm);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
* HashMap<String,Student>
* 键:String 学号
* 值:Student 学生对象
*/
public class HashMapDemo3 {
public static void main(String[] args) {
// 创建集合对象
HashMap<String, Student> hm = new HashMap<String, Student>();

// 创建学生对象
Student s1 = new Student("周星驰", 58);
Student s2 = new Student("刘德华", 55);
Student s3 = new Student("梁朝伟", 54);
Student s4 = new Student("刘嘉玲", 50);
Student s5 = new Student("刘嘉玲", 50);

// 添加元素
hm.put("9527", s1);
hm.put("9522", s2);
hm.put("9524", s3);
hm.put("9529", s4);
hm.put("9520", s5);

// 遍历
Set<String> set = hm.keySet();
for (String key : set) {
// 注意了:这次值不是字符串了
// String value = hm.get(key);
Student value = hm.get(key);
System.out.println(key + "---" + value.getName() + "---" + value.getAge());
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
* HashMap<Student,String>
* 键:Student
* 要求:如果两个对象的成员变量值都相同,则为同一个对象。
* 值:String
*/
public class HashMapDemo4 {
public static void main(String[] args) {
// 创建集合对象
HashMap<Student, String> hm = new HashMap<Student, String>();

// 创建学生对象
Student s1 = new Student("貂蝉", 27);
Student s2 = new Student("王昭君", 30);
Student s3 = new Student("西施", 33);
Student s4 = new Student("杨玉环", 35);
Student s5 = new Student("貂蝉", 27);

// 添加元素
hm.put(s1, "8888");
hm.put(s2, "6666");
hm.put(s3, "5555");
hm.put(s4, "7777");
hm.put(s5, "9999");

// 遍历
Set<Student> set = hm.keySet();
for (Student key : set) {
String value = hm.get(key);
System.out.println(key.getName() + "---" + key.getAge() + "---"
+ value);
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
* LinkedHashMap:是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。
* 由哈希表保证键的唯一性
* 由链表保证键盘的有序(存储和取出的顺序一致)
*/
public class LinkedHashMapDemo {
public static void main(String[] args) {
// 创建集合对象
LinkedHashMap<String, String> hm = new LinkedHashMap<String, String>();

// 创建并添加元素
hm.put("2345", "hello");
hm.put("1234", "world");
hm.put("3456", "java");
hm.put("1234", "javaee");
hm.put("3456", "android");

// 遍历
Set<String> set = hm.keySet();
for (String key : set) {
String value = hm.get(key);
System.out.println(key + "---" + value);
}
}
}

Hashtable集合练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
* 1:Hashtable和HashMap的区别?
* Hashtable:线程安全,效率低。不允许null键和null值
* HashMap:线程不安全,效率高。允许null键和null值
*
* 2:List,Set,Map等接口是否都继承子Map接口?
* List,Set不是继承自Map接口,它们继承自Collection接口
* Map接口本身就是一个顶层接口
*/
public class HashtableDemo {
public static void main(String[] args) {
// HashMap<String, String> hm = new HashMap<String, String>();
Hashtable<String, String> hm = new Hashtable<String, String>();

hm.put("it001", "hello");
// hm.put(null, "world"); //NullPointerException
// hm.put("java", null); // NullPointerException

System.out.println(hm);
}
}

TreeMap集合练习

  A:TreeMap<String,String>

  B:TreeMap<Student,String>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
* TreeMap:是基于红黑树的Map接口的实现。
*
* HashMap<String,String>
* 键:String
* 值:String
*/
public class TreeMapDemo {
public static void main(String[] args) {
// 创建集合对象
TreeMap<String, String> tm = new TreeMap<String, String>();

// 创建元素并添加元素
tm.put("hello", "你好");
tm.put("world", "世界");
tm.put("java", "爪哇");
tm.put("world", "世界2");
tm.put("javaee", "爪哇EE");

// 遍历集合
Set<String> set = tm.keySet();
for (String key : set) {
String value = tm.get(key);
System.out.println(key + "---" + value);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*
* TreeMap<Student,String>
* 键:Student
* 值:String
*/
public class TreeMapDemo2 {
public static void main(String[] args) {
// 创建集合对象
TreeMap<Student, String> tm = new TreeMap<Student, String>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 主要条件
int num = s1.getAge() - s2.getAge();
// 次要条件
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
return num2;
}
});

// 创建学生对象
Student s1 = new Student("潘安", 30);
Student s2 = new Student("柳下惠", 35);
Student s3 = new Student("唐伯虎", 33);
Student s4 = new Student("唐伯虎", 33);
Student s5 = new Student("唐伯虎", 34);

// 存储元素
tm.put(s1, "宋朝");
tm.put(s2, "元朝");
tm.put(s3, "明朝");
tm.put(s4, "汉朝");
tm.put(s5, "汉朝");

// 遍历
Set<Student> set = tm.keySet();
for (Student key : set) {
String value = tm.get(key);
System.out.println(key.getName() + "---" + key.getAge() + "---" + value);
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

案例

​ A:统计一个字符串中每个字符出现的次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/*
* 需求 :"abcdeabcdabcaba",获取字符串中每一个字母出现的次数要求结果:a(5)b(4)c(3)d(2)e(1)
*
* 分析:
* A:定义一个字符串(可以改进为键盘录入)
* B:定义一个TreeMap集合
* 键:Character
* 值:Integer
* C:把字符串转换为字符数组
* D:遍历字符数组,得到每一个字符
* E:拿刚才得到的字符作为键到集合中去找值,看返回值
* 是null:说明该键不存在,就把该字符作为键,1作为值存储
* 不是null:说明该键存在,就把值加1,然后重写存储该键和值
* F:定义字符串缓冲区变量
* G:遍历集合,得到键和值,进行按照要求拼接
* H:把字符串缓冲区转换为字符串输出
*
* 录入:linqingxia
* 结果:result:a(1)g(1)i(3)l(1)n(2)q(1)x(1)
*/
public class TreeMapDemo {
public static void main(String[] args) {
// 定义一个字符串(可以改进为键盘录入)
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String line = sc.nextLine();

// 定义一个TreeMap集合
TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();

// 把字符串转换为字符数组
char[] chs = line.toCharArray();

// 遍历字符数组,得到每一个字符
for (char ch : chs) {
// 拿刚才得到的字符作为键到集合中去找值,看返回值
Integer i = tm.get(ch);

// 是null:说明该键不存在,就把该字符作为键,1作为值存储
if (i == null) {
tm.put(ch, 1);
} else {
// 不是null:说明该键存在,就把值加1,然后重写存储该键和值
i++;
tm.put(ch, i);
}
}

// 定义字符串缓冲区变量
StringBuilder sb = new StringBuilder();

// 遍历集合,得到键和值,进行按照要求拼接
Set<Character> set = tm.keySet();
for (Character key : set) {
Integer value = tm.get(key);
sb.append(key).append("(").append(value).append(")");
}

// 把字符串缓冲区转换为字符串输出
String result = sb.toString();
System.out.println("result:" + result);
}
}

  B:集合的嵌套遍历

    a:HashMap嵌套HashMap

    b:HashMap嵌套ArrayList

    c:ArrayList嵌套HashMap

    d:多层嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
* HashMap嵌套HashMap
*
* Java培训班
* 基础班
* 陈玉楼 20
* 高跃 22
* 就业班
* 李杰 21
* 曹石磊 23
*
* 先存储元素,然后遍历元素
*/
public class HashMapDemo {
public static void main(String[] args) {
// 创建集合对象
HashMap<String, HashMap<String, Integer>> javaMap = new HashMap<String, HashMap<String, Integer>>();

// 创建基础班集合对象
HashMap<String, Integer> jcMap = new HashMap<String, Integer>();
// 添加元素
jcMap.put("陈玉楼", 20);
jcMap.put("高跃", 22);
// 把基础班添加到大集合
javaMap.put("基础班", jcMap);

// 创建就业班集合对象
HashMap<String, Integer> jyMap = new HashMap<String, Integer>();
// 添加元素
jyMap.put("李杰", 21);
jyMap.put("曹石磊", 23);
// 把基础班添加到大集合
javaMap.put("就业班", jyMap);

// 遍历集合
Set<String> javaMapSet = javaMap.keySet();
for (String javaMapKey : javaMapSet) {
System.out.println(javaMapKey);
HashMap<String, Integer> javaMapValue = javaMap.get(javaMapKey);
Set<String> javaMapValueSet = javaMapValue.keySet();
for (String javaMapValueKey : javaMapValueSet) {
Integer javaMapValueValue = javaMapValue.get(javaMapValueKey);
System.out.println("\t" + javaMapValueKey + "---" + javaMapValueValue);
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
* HashMap嵌套ArrayList
*
* 三国演义
* 吕布
* 周瑜
* 笑傲江湖
* 令狐冲
* 林平之
* 神雕侠侣
* 郭靖
* 杨过
*
* 先存储元素,然后遍历元素
*/
public class HashMapIncludeArrayListDemo {
public static void main(String[] args) {
// 创建集合对象
HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();

// 创建元素集合1
ArrayList<String> array1 = new ArrayList<String>();
array1.add("吕布");
array1.add("周瑜");
hm.put("三国演义", array1);

// 创建元素集合2
ArrayList<String> array2 = new ArrayList<String>();
array2.add("令狐冲");
array2.add("林平之");
hm.put("笑傲江湖", array2);

// 创建元素集合3
ArrayList<String> array3 = new ArrayList<String>();
array3.add("郭靖");
array3.add("杨过");
hm.put("神雕侠侣", array3);

// 遍历集合
Set<String> set = hm.keySet();
for (String key : set) {
System.out.println(key);
ArrayList<String> value = hm.get(key);
for (String s : value) {
System.out.println("\t" + s);
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
* ArrayList嵌套HashMap。
*
* 结果:
* 周瑜---小乔
* 吕布---貂蝉
*
* 郭靖---黄蓉
* 杨过---小龙女
*
* 令狐冲---任盈盈
* 林平之---岳灵珊
*
* 先存储元素,然后遍历元素
*/
public class ArrayListIncludeHashMapDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList<HashMap<String, String>> array = new ArrayList<HashMap<String, String>>();

// 创建元素1
HashMap<String, String> hm1 = new HashMap<String, String>();
hm1.put("周瑜", "小乔");
hm1.put("吕布", "貂蝉");
// 把元素添加到array里面
array.add(hm1);

// 创建元素1
HashMap<String, String> hm2 = new HashMap<String, String>();
hm2.put("郭靖", "黄蓉");
hm2.put("杨过", "小龙女");
// 把元素添加到array里面
array.add(hm2);

// 创建元素1
HashMap<String, String> hm3 = new HashMap<String, String>();
hm3.put("令狐冲", "任盈盈");
hm3.put("林平之", "岳灵珊");
// 把元素添加到array里面
array.add(hm3);

// 遍历
for (HashMap<String, String> hm : array) {
Set<String> set = hm.keySet();
for (String key : set) {
String value = hm.get(key);
System.out.println(key + "---" + value);
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
* 多层嵌套
*
* 为了更符合要求:这次的数据就看成是学生对象。
*
* Java培训班
* bj 北京校区
* jc 基础班
* 林青霞 27
* 风清扬 30
* jy 就业班
* 赵雅芝 28
* 武鑫 29
* sh 上海校区
* jc 基础班
* 郭美美 20
* 犀利哥 22
* jy 就业班
* 罗玉凤 21
* 马征 23
* gz 广州校区
* jc 基础班
* 王力宏 30
* 李静磊 32
* jy 就业班
* 郎朗 31
* 柳岩 33
* xa 西安校区
* jc 基础班
* 范冰冰 27
* 刘意 30
* jy 就业班
* 李冰冰 28
* 张志豪 29
*/
public class HashMapDemo {
public static void main(String[] args) {
// 创建大集合
HashMap<String, HashMap<String, ArrayList<Student>>> javaMap = new HashMap<String, HashMap<String, ArrayList<Student>>>();

// 北京校区数据
HashMap<String, ArrayList<Student>> bjjavaMap = new HashMap<String, ArrayList<Student>>();
ArrayList<Student> array1 = new ArrayList<Student>();
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("巩俐", 30);
array1.add(s1);
array1.add(s2);
ArrayList<Student> array2 = new ArrayList<Student>();
Student s3 = new Student("赵雅芝", 28);
Student s4 = new Student("武鑫", 29);
array2.add(s3);
array2.add(s4);
bjjavaMap.put("基础班", array1);
bjjavaMap.put("就业班", array2);
javaMap.put("北京校区", bjjavaMap);

// 上海校区数据就不写了
// 广州校区数据就不写了

// 西安校区数据
HashMap<String, ArrayList<Student>> xajavaMap = new HashMap<String, ArrayList<Student>>();
ArrayList<Student> array3 = new ArrayList<Student>();
Student s5 = new Student("范冰冰", 27);
Student s6 = new Student("刘意", 30);
array3.add(s5);
array3.add(s6);
ArrayList<Student> array4 = new ArrayList<Student>();
Student s7 = new Student("李冰冰", 28);
Student s8 = new Student("张志豪", 29);
array4.add(s7);
array4.add(s8);
xajavaMap.put("基础班", array3);
xajavaMap.put("就业班", array4);
javaMap.put("西安校区", xajavaMap);

// 遍历集合
Set<String> javaMapSet = javaMap.keySet();
for (String javaMapKey : javaMapSet) {
System.out.println(javaMapKey);
HashMap<String, ArrayList<Student>> javaMapValue = javaMap.get(javaMapKey);
Set<String> javaMapValueSet = javaMapValue.keySet();
for (String javaMapValueKey : javaMapValueSet) {
System.out.println("\t" + javaMapValueKey);
ArrayList<Student> javaMapValueValue = javaMapValue.get(javaMapValueKey);
for (Student s : javaMapValueValue) {
System.out.println("\t\t" + s.getName() + "---" + s.getAge());
}
}
}
}
}

class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

Collections集合工具类

介绍

Collections 是针对集合进行操作的工具类,都是静态方法。

Collection和Collections

  A:Collection 是单列集合的顶层接口,有两个子接口List和Set

  B:Collections 是针对集合进行操作的工具类,可以对集合进行排序和查找等

常用方法

1
2
3
4
5
6
  A:    public static <T extends Comparable<? super T>> void sort(List<T> list):根据元素的自然顺序 对指定列表按升序进行排序。
     public static <T> void sort(List<T> list, Comparator<? super T> c):根据指定比较器产生的顺序对指定列表进行排序。
  B: public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key):使用二分搜索法搜索指定列表,以获得指定对象。
  C: public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll):根据元素的自然顺序,返回给定 collection 的最大元素。
  D: public static void reverse(List<?> list):反转指定列表中元素的顺序。
  E: public static void shuffle(List<?> list):使用默认随机源对指定列表进行置换。所有置换发生的可能性都是大致相等的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class CollectionsDemo {
public static void main(String[] args) {
// 创建集合对象
ArrayList<Integer> list = new ArrayList<Integer>();

// 添加元素
list.add(30);
list.add(20);
list.add(50);
list.add(10);
list.add(40);

System.out.println("list:" + list);// list:[30, 20, 50, 10, 40]

// public static <T> void sort(List<T> list):排序 默认情况下是自然顺序。
// Collections.sort(list);
// System.out.println("list:" + list);// list:[10, 20, 30, 40, 50]

// public static <T> int binarySearch(List<?> list,T key):二分查找
System.out.println("binarySearch:" + Collections.binarySearch(list, 30));// binarySearch:0
System.out.println("binarySearch:" + Collections.binarySearch(list, 300));// binarySearch:-6
System.out.println("binarySearch:" + Collections.binarySearch(list, 3));// binarySearch:-1

// public static <T> T max(Collection<?> coll):最大值
System.out.println("max:" + Collections.max(list));// max:50

// public static void reverse(List<?> list):反转
// Collections.reverse(list);
// System.out.println("list:" + list);// list:[40, 10, 50, 20, 30]

// public static void shuffle(List<?> list):随机置换
// Collections.shuffle(list);
// System.out.println("list:" + list);
}
}

案例

  A:ArrayList集合存储自定义对象的排序

  B:模拟斗地主洗牌和发牌

  C:模拟斗地主洗牌和发牌并对牌进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
* Collections可以针对ArrayList存储基本包装类的元素排序,存储自定义对象可不可以排序呢?
*/
public class CollectionsDemo {
public static void main(String[] args) {
// 创建集合对象
List<Student> list = new ArrayList<Student>();

// 创建学生对象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("风清扬", 30);
Student s3 = new Student("刘晓曲", 28);
Student s4 = new Student("武鑫", 29);
Student s5 = new Student("林青霞", 27);

// 添加元素对象
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
list.add(s5);

// 排序
// 1.自然排序:Collections.sort(list);
// 2.比较器排序
// 如果同时有自然排序和比较器排序,以比较器排序为主
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getAge() - s1.getAge();
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
return num2;
}
});

// 遍历集合
for (Student s : list) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}

class Student implements Comparable<Student> {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public int compareTo(Student s) {
int num = this.age - s.age;
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
return num2;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*
* 模拟斗地主洗牌和发牌
*
* 分析:
* A:创建一个牌盒
* B:装牌
* C:洗牌
* D:发牌
* E:看牌
*/
public class PokerDemo {
public static void main(String[] args) {
// 创建一个牌盒
ArrayList<String> arrayList = new ArrayList<String>();

// 装牌
// 黑桃A,黑桃2,黑桃3,...黑桃K
// 红桃A,...
// 梅花A,...
// 方块A,...
// 定义一个花色数组
String[] colors = { "♠", "♥", "♣", "♦" };
// 定义一个点数数组
String[] numbers = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };
// 装牌
for (String color : colors) {
for (String number : numbers) {
arrayList.add(color.concat(number));// 将指定字符串连接到此字符串的结尾。 "cares".concat("s") returns "caress"
}
}
arrayList.add("小王");
arrayList.add("大王");

// 洗牌
Collections.shuffle(arrayList);

// System.out.println("arrayList:" + arrayList);

// 发牌
ArrayList<String> liuDeHua = new ArrayList<String>();
ArrayList<String> linQingXia = new ArrayList<String>();
ArrayList<String> liuYi = new ArrayList<String>();
ArrayList<String> diPai = new ArrayList<String>();

for (int x = 0; x < arrayList.size(); x++) {
if (x >= arrayList.size() - 3) {
diPai.add(arrayList.get(x));
} else if (x % 3 == 0) {
liuDeHua.add(arrayList.get(x));
} else if (x % 3 == 1) {
linQingXia.add(arrayList.get(x));
} else if (x % 3 == 2) {
liuYi.add(arrayList.get(x));
}
}

// 看牌
lookPoker("刘德华", liuDeHua);
lookPoker("林青霞", linQingXia);
lookPoker("刘意", liuYi);

lookPoker("底牌", diPai);
}

public static void lookPoker(String name, ArrayList<String> array) {
System.out.print(name + "的牌是:");
for (String s : array) {
System.out.print(s + " ");
}
System.out.println();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
* 思路:
* A:创建一个HashMap集合
* B:创建一个ArrayList集合
* C:创建花色数组和点数数组
* D:从0开始往HashMap里面存储编号,并存储对应的牌
* 同时往ArrayList里面存储编号即可。
* E:洗牌(洗的是编号)
* F:发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收)
* G:看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)
*/
public class PokerDemo {
public static void main(String[] args) {
// 创建一个HashMap集合
HashMap<Integer, String> hm = new HashMap<Integer, String>();

// 创建一个ArrayList集合
ArrayList<Integer> array = new ArrayList<Integer>();

// 创建花色数组和点数数组
// 定义一个花色数组
String[] colors = { "♠", "♥", "♣", "♦" };
// 定义一个点数数组
String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2", };

// 从0开始往HashMap里面存储编号,并存储对应的牌,同时往ArrayList里面存储编号即可。
int index = 0;

for (String number : numbers) {
for (String color : colors) {
String poker = color.concat(number);
hm.put(index, poker);
array.add(index);
index++;
}
}
hm.put(index, "小王");
array.add(index);
index++;
hm.put(index, "大王");
array.add(index);

// 洗牌(洗的是编号)
Collections.shuffle(array);

// 发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收)
TreeSet<Integer> fengQingYang = new TreeSet<Integer>();
TreeSet<Integer> linQingXia = new TreeSet<Integer>();
TreeSet<Integer> liuYi = new TreeSet<Integer>();
TreeSet<Integer> diPai = new TreeSet<Integer>();

for (int x = 0; x < array.size(); x++) {
if (x >= array.size() - 3) {
diPai.add(array.get(x));
} else if (x % 3 == 0) {
fengQingYang.add(array.get(x));
} else if (x % 3 == 1) {
linQingXia.add(array.get(x));
} else if (x % 3 == 2) {
liuYi.add(array.get(x));
}
}

// 看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)
lookPoker("风清扬", fengQingYang, hm);
lookPoker("林青霞", linQingXia, hm);
lookPoker("刘意", liuYi, hm);
lookPoker("底牌", diPai, hm);
}

// 写看牌的功能
public static void lookPoker(String name, TreeSet<Integer> ts, HashMap<Integer, String> hm) {
System.out.print(name + "的牌是:");
for (Integer key : ts) {
String value = hm.get(key);
System.out.print(value + " ");
}
System.out.println();
}
}

常见数据结构

先进后出

队列

先进先出

img

数组

查询快,增删慢

链表

查询慢,增删快

img

img

哈希表

是一个元素为链表的数组。综合了数组和链表的好处。