集合引入,Collection接口的方法, 迭代器


Java 集合

1.引入:

  1. 集合是一个容器,是一个载体,可以依次容纳多个对象,数组就是一个集合;
  2. 集合是存储引用数据类型,不能存储基本数据类型,也不能直接存储java对象,存的是java对象的内存地址
  3. 集合本身就是一个引用对象,一个大的容器
  4. 在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中存储元素,等于将数据放到不同的数据结构中;数据结构就是数据的存储结构,常见的数据结构有:数组,二叉树,链表,哈希表等;所以使用不同的集合就是使用了不同的数据结构
  5. java中已经将数据结构实现了,就是已经写好了的一些常用的集合类(集合实现类),要选择在什么情况下选择合适的集合去使用即可
  6. 所有的集合类(集合实现类)和 集合接口都在java.util 包下

7. 集合框架(集合继承结构):整个集合框架就围绕一组标准接口而设计

  1. 在java中的集合分为两大类:
    一类是单个方式存储元素,这一类集合中的超级父接口:java.util.Collection
    一类是以键值对的方式存储元素,这一类集合中的超级父接口:java.util.Map

  2. Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。

  3. 集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:

接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象

实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。

算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。

除了集合,该框架也定义了几个 Map 接口和类。Map 里存储的是键/值对。尽管 Map 不是集合,但是它们完全整合在集合中。

2. Collection 接口

  1. 超级父接口是Iterable接口:
    Iterable意思是可迭代的,可遍历的,所有集合元素都是可迭代的,可遍历的
    Iterable接口中有一个 Iterator() 方法,返回一个Iterator对象
    Iterator是叫集合的迭代器对象,Collection 接口继承了Iterable接口,就可以直接调用这个方法,通过这个迭代器去迭代这个集合中的元素对象

迭代器对象Iterator接口,里面有方法:hasNext() next() remove()

Collection 接口和Iterator接口是关联关系(has a),和Iterable接口是泛化/继承关系(is a)
在UML图中,继承是空心三角形实线指向父,实现关系(like a)是空心三角形虚线指向父,关联关系是带箭头的实线

Collection 接口的子类型:List接口、Set 接口

  1. Collection 接口:

Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素; Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。当然,它的子接口还有很多,只学习常用的
Collection 接口存储一组不唯一,无序的对象。

  1. List接口:有序可重复,元素有下标

List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。
List 接口存储一组不唯一,有序(插入顺序)的对象。

有序:存进去的顺序和取出来的顺序相同,不是大小排序
可重复:已经有个1,还可以再放个1

  1. Set 接口:无序不可重复,元素没有下标
    Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。
    Set 接口存储一组唯一,无序的对象。

集合实现类(集合类):Java提供了一套实现了Collection接口的标准集合类。其中一些是具体类,这些类可以直接拿来使用,而另外一些是抽象类,提供了接口的部分实现。

以下仅仅是常用的:

  1. 实现List接口 :ArrayList类,LinkedList类 ,Vector类
  2. 实现Set接口:HashSet类;SortedSet接口是Set接口的子接口,SortedSet接口的实现类:TreeSet类实现了Set接口;

(1)ArrayList类:底层采取了数组这种数据结构,实现了可变大小的数组,是非线程安全的
(2)LinkedList类 :底层采取了双向链表这种数据结构
(3)Vector类:底层采取了数组这种数据结构,是线程安全的,效率较低,使用较少

(1)HashSet类:底层采取了哈希表这种数据结构,实际上HashSet集合在new的时候,底层是new了一个HashMap集合,向HashSet集合存储元素,实际上是存储到HashMap集合中了

(2)SortedSet接口:由于继承了Set接口,其特点有无序不可重复,没有下标,但放在SortedSet集合中的元素可以自动排序,我们成为可排序集合

(3)SortedSet接口的实现类的TreeSet类:底层采取了二叉树这种数据结构,实际上TreeSet集合在new的时候,底层是new了一个TreeMap集合,向TreeSet集合存储元素,实际上是存储到TreeMap集合中了

3.Map集合(Map接口)

  1. Map接口和Collection 接口没有关系
  2. Map集合以key和value的这种键值对的方式存储元素,key和value都是存储java对象的内存地址,所有Map集合的key都是无序不可重复的,就是说Map集合的key和Set集合存储元素的特点相同,Map集合的key,就是一个Set集合,往Set集合中放数据,实际上放到Map集合的key部分
  3. 其实现类:
    (1)HashMap 类
    (2)Hashtable类,其子类是Properties
  4. 子接口:
    SortedMap接口:其实现类有TreeMap类

(1)HashMap 类:底层采取了哈希表这种数据结构,是非线程安全的

(2)Hashtable类:底层采取了哈希表这种数据结构,是线程安全的,使用较少

(3)Hashtable类的子类是Properties:底层采取了哈希表这种数据结构,表示一个持久的属性集,存储元素时,也是采取key和value的形式,属性列表中每个键及其对应值都是一个字符串。

(4)SortedMap接口:由于SortedMap集合是Map接口的子接口,key都是无序不可重复的,同时,放在SortedMap集合key部分的元素会自动按照大小顺序排序,成为可排序的集合

(5)SortedMap接口的实现类有TreeMap类:底层采取了二叉树这种数据结构,key部分的元素自然会自动按照大小顺序排序,

2. Collection 接口中常用的方法

  1. 在没有使用泛型之前,Collection可以存储Object的所有子类型,(但牢记集合中不能直接存储基本数据类型,也不存储java对象),使用泛型之后,Collection中只能存储某个具体的类型

2. Collection 接口里面都是抽象方法:

方法1. boolean add(Object e); 向集合中添加元素
方法2. int size(); 获取集合中元素的个数
方法3.void clear(); 清空集合
方法4. boolean contains(Object o); 判断集合中是否包含元素o,包含返回true
方法5. boolean remove(Object o); 删除集合中的元素o
方法6. boolean isEmpty(); 判断集合是否为空
方法7. Object[] toArray(); 将集合转换为数组

package 集合;
//都需要导入java.util包
import java.util.ArrayList;
import java.util.Collection;


public class Jihe01 {

	public static void main(String[] args) {
		 //创建一个集合对象
		//Collection c = new Collection();报错,因为接口是抽象的,不可以实例化
		//多态
		Collection c = new ArrayList();
//		方法1. boolean add(Object e); 向集合中添加元素
		c.add(200);//自动装箱,实际上是放进去一个对象的内存地址,Integer x = new Integer(200); c.add(x);
		c.add(3.14);//自动装箱,实际上是放进去一个对象的内存地址 Double x  = new Double(3.14);c.add(x);
		c.add(true);//自动装箱
		
//		方法2. int size(); 获取集合中元素的个数
		System.out.println(c.size());//3
		
//		方法3.void clear(); 清空集合
		c.clear();
		System.out.println(c.size());//0
		
//		方法4. boolean contains(Object o); 判断集合中是否包含元素o,包含返回true
		c.add("加油");
		
		System.out.println(c.contains("加油"));//true
		
//		方法5. boolean remove(Object o); 删除集合中的元素o
		c.remove("加油");
		System.out.println(c.size());//0
		
//		方法6. boolean isEmpty(); 判断集合是否为空
		System.out.println(c.isEmpty());//true
		
//		方法7.  Object[] toArray(); 将集合转换为数组
		c.add(200);
		c.add(3.14);
		c.add("加油");
		c.add(new Object());
		c.add(new Student());
		Object[] obj = c.toArray();
		for(int i=0;i

3.关于集合遍历或迭代:(以下讲解的遍历方式或迭代方式是所有的Collection通用的一种方式,在所有的Collection及其子类中使用,在Map中不能用)

单独拿出来讲“ Collection 接口调用 iterator()方法来获取一个迭代器对象Iterator”

package 集合;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class Jihe02 {

	public static void main(String[] args) {
	 //创建集合对象,用到多态
		Collection c = new HashSet();
	//添加元素
		c.add(200);
		c.add(3.14);
		c.add("加油");
		c.add(new Object());
//		对集合Collection进行迭代/遍历:
//		首先,获取集合对象的迭代器对象Iterator
//		第二步:通过迭代器对象Iterator中的方法完成对集合对象的遍历或迭代,
		/*迭代器Iterator(Iterator接口)共有三种方法:
		 * 1.  boolean hasNext(); 若仍有元素可以迭代,则返回true
		 * 2.  Object next(); 返回迭代的下一个元素(就是指这个方法让迭代器前进一位,并且将指向的元素返回)
		 * 迭代器最初并没有指向第一个元素对象,先hasNext()判断有元素可以迭代吗?有,则调用next(),让迭代器前进一位
		 * 依次将元素将集合中的元素取出
		 * boolean hasNext = it.hasNext();
		if(hasNext) {
			Object obj = it.next();
			System.out.println(obj);
		}
		应该使用循环来实现将集合中的元素依次取出*/
		Iterator it = c.iterator();
		while(it.hasNext()) {
			Object obj = it.next();
			System.out.println(obj);
		}
/*加油
3.14
200
java.lang.Object@7de26db8
*/	
	}
}
package 集合;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class Jihe0202 {

	public static void main(String[] args) {
		//创建集合对象,用到多态
		Collection c = new HashSet();
		//添加元素
		c.add(1);//自动装箱,就是Integer x = new Integer(1); c.add(x);
		c.add(11);
		c.add(111);
		//获取迭代器,循环迭代
		Iterator it = c.iterator();
		while(it.hasNext()) {
			Object obj = it.next();
			if(obj instanceof Integer) {
				System.out.println("Integer型对象");
			}
			System.out.println(obj);
		}
/*想说明:
 * 在集合中传进去什么类型的数据,取出时仍然是什么类型的数据
 * 上面是传进去了Integer对象,取出仍是Integer对象
 * 只不过在输出时,有println(obj)方法:
 * 源码:
 *  public void println(Object x) {
        String s = String.valueOf(x);
        }
        将输出对象都转换为String类型的,同时,String类重写了toString()方法*/
	}
	/*
 Integer型对象
1
Integer型对象
11
Integer型对象
111*/

}

当集合结构发生改变时(例如 增添或删除个别元素时),没有重新获取迭代器

package 集合;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Jihe02020 {

	public static void main(String[] args) {
		 
				Collection c = new  ArrayList();
				
//				 如果在集合中是空时,就获取迭代器,添加元素后,
//				就是集合结构发生改变时,没有重新获取迭代器
//			出现异常:java.util.ConcurrentModificationException
//				Iterator it = c.iterator();	
				
				//添加元素
				c.add(1); 
				c.add(11);
				c.add(111);
				Iterator it = c.iterator();	
				while(it.hasNext()) {
					Object obj = it.next();
					System.out.println(obj);
				}
				
				//删除元素后,重新获取迭代器
				c.remove(11);
				Iterator i = c.iterator();	
				while(i.hasNext()) {
					Object obj = i.next();
					System.out.println(obj);
				}
				
				//迭代器Iterator接口中的第三个方法:
				/*default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    就是remove()方法,删除的是迭代器当前指向的元素*/
				
				
				c.add(200); 	
				Iterator j = c.iterator();	
				while(j.hasNext()) {
					Object obj = j.next();
					System.out.println(obj);
					j.remove();
				}
				
				System.out.println(c.size());
	}
/*
1
11
111
1
111
1
111
200
0
*/
}

4. Collection 接口里面的:contains方法 中底层会调用调用了equals方法进行比对,来判断判断集合中是否包含某个元素,所以存放在一个集合中的类型,一定要重写equals方法;同时,记住:String类和Integer类都已经重写了equals方法;

package 集合;

import java.util.ArrayList;
import java.util.Collection;
 

public class Jihe03 {
//深入Collection 集合中的contains方法:
//	boolean contains(Object o); 判断集合中是否包含元素o,包含返回true
	public static void main(String[] args) {
		Collection c = new ArrayList();
		
		String s1 = new String("abc");
		c.add(s1);
		String s2 = new String("abcd");
		c.add(s2);
		
		String s3 = new String("abc");
//		s3并没有添加到集合c中
//		那c集合中是否包含元素s3呢?
		System.out.println(c.contains(s3));//true
		
		/*分析:
		 *关键看底层的源代码:
		 *在ArrayList中找到contains方法,
		 *public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    然后在indexOf(o)中:
     if (o.equals(es[i])) {
                    return i;
                }
       调用了equals方法,
       其中的o是s3,es[i]是s1 
       就是 s3.equals(s1)
       分析:
      在堆中中new出了两个String对象s1 和 s3 ,
      s1 和 s3中都保存的是在方法区的常量池中的同一个字符串"abc"的内存地址,
       向右赋值,给了栈中的两个变量  s1 和 s3,
       此时的实例变量s1 和 s3 中保存的是 两个String对象s1 和 s3 在堆中的内存地址
       然后,s1的内存地址送到集合 c 的ArrayList数组中,s3并没有添加到集合c中,
       但因为底层的contains方法调用了equals方法,
       因为String类的equals方法是重写了,比较的是两个元素的内容,
       因为s1 和 s3保存的内容都是字符串"abc"
       所以c.contains(s3) 就是相当于 s3 也在集合c中
             
		 * */
	}

}

放在集合中的元素一定要重写equals方法

package 集合;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

public class Jihe0303 {

	public static void main(String[] args) {
		// 创建集合对象,用到多态
		Collection c = new ArrayList();
		// 创建用户对象
		User u1 = new User("jack");
		User u2 = new User("jack");

		// 添加元素
		c.add(u1);

		// System.out.println(c.contains(u2));//false
		/*
		 * contains方法 中底层会调用调用了equals方法进行比对,因为User类没有重写equals方法
		 * 所以此处调用Object类中的equals方法,它是用“==”,就是比较两个元素对象的内存地址 就是 u1.equals(u2) 是 false
		 */

//		重写User类中的equals方法后
		System.out.println(c.contains(u2));// true
	}
}

class User {

	public String name;

	public User() {
	}

	public User(String name) {
		this.name = name;
	}

	// 重写equals方法,就是姓名一样,就可以认为同一个用户
	@Override
	public boolean equals(Object obj) {
		if (obj == null || !(obj instanceof User)) {
			return false;
		}
		if (obj == this) {
			return true;
		}
		User s = (User) obj;
		if (s.name.equals(this.name)) {
			return true;
		}
		return false;
	}

}

4. Collection 接口里面的:remove方法 ; 因为底层调用了equals方法

//创建集合对象
		Collection cc = new ArrayList(); 
		
		
		String s1 = new String("abc");
		cc.add(s1);
		
		String s2 = new String("abc");
		cc.remove(s2);
		
		System.out.println(cc.size());//0
		
		/*分析:因为contains方法在确认元素属于集合时,底层调用了equals方法,所以s1和s2认为是一样的,
		 * 删除其中一个,就认为同时删除了
		 * */

相关