集合框架总结(基础知识)

集合框架总结

一、集合框架概述

1、集合的由来:

我们学习的是面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,我们就必须把这多个对象进行存储。而要想存储多个对象,就不能是一个基本的变量,而应该是一个容器类型的变量,在我们目前所学过的知识里面,有哪些是容器类型的呢?数组和StringBuffer。但是呢?StringBuffer的结果是一个字符串,不一定满足我们的要求,所以我们只能选择数组,这就是对象数组。而对象数组又不能适应变化的需求,因为数组的长度是固定的,这个时候,为了适应变化的需求,Java就提供了集合类供我们使用。

2、数组和集合的区别?

A:长度区别:数组的长度固定,集合长度可变
B:内容不同:数组存储的是同一种类型的元素,而集合可以存储不同类型的元素
C:元素的数据类型问题:数组可以存储基本数据类型,也可以存储引用数据类型,集合只能存储引用类型

根据存储元素的数据结构,有很多集合与之对应,我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。

3、集合的继承体系结构

请看下面的这张图:


集合体系理解:先看中间部分,超级类是collection,接口collection中有两个子接口,List和Set,Set:元素是无序的(取出和存入的顺序是不一致的),元素不可重复, Set集合的功能和Collection的功能是一样的  ,List中的元素是有序的,即有索引。List接口中有三个(一个图为画出)具体的类,ArrayList,LinkedList,Vector,ArrayList底层数据结构是基于数组的,LinkedList底层数据结构是基于链表的,Vector底层数据结构也是基于数组的,可以看到ArrayList和Vector的存储方式有重复,为什么呢?因为集合框架是从JDK1.2版本出现的,而Vector是从JDK1.0开始的,Vector是元老级别的,当然新版本的出现必须兼容老版本,所以有了新容器,Vector用的也就少了,其他两个容器选用哪一个,当然看需求,主要评估因素是集合增删查改的频繁程度,两个类除了拥有父类Collection中的方法外,也有自己的特性方法,不过大差不差。Set接口也有两个子类,HashSet和TreeSet,其中HashSet的底层数据结构是基于哈希表的,

TreeSet的底层数据结构是基于二叉树的。

二、集合类介绍

  现在我们对集合的顶层接口Collection的功能进行一下归纳

1、Collection的功能概述:

(1).添加功能

       boolean add(Object obj):添加一个元素
       boolean addAll(Collection c):添加一个集合的元素

(2).删除功能

void clear():移除所有元素
        boolean remove(Object o):移除一个元素
boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)

(3).判断功能

boolean contains(Object o):判断集合中是否包含指定的元素
  boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)
  boolean isEmpty():判断集合是否为空

(4):获取功能

Iterator<E> iterator()(重点)

(5).长度功能

int size():元素的个数
  面试题:数组有没有length()方法呢?字符串有没有length()方法呢?集合有没有length()方法呢?

(6).交集功能

boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?

(7).把集合转换为数组

  Object[] toArray()

2、List的功能概述

(1).元素有序,可以重复

(2).注意事项:

对集合的操作方式有两种,第一种是集合自身具有的方法,第二种是用迭代器存放集合元素引用来操作集合,一个类同时具有两种操作方式,这就可能产生冲突。
代码演示如下:
String s=“java”;
Iterator it=al.iterator();
While(it.hasNext)
{
   Object obj=it.next();
   If(obj.equals(s))
    {
       al.add(“java01”);
    }
}

代码分析:
   当Iterator it=al.iterator();执行时,迭代器就已经知道集合中所有元素的引 用,当 al.add(“java01”);再次添加元素时,迭代器是不知道的,这就造成了两 者的不一致,JVM会抛出     ConcurrentModificationException异常。因为迭代器仅有三个方法,我想要用迭代器方式进行添加怎么办呢?因为迭代器的本身局限性,就诞生出它的一个小弟,特地针对List.这个小弟就是ListIterator,它不仅可以实现add()方法,还可以正向和逆向遍历。


3、ArrayList的功能概述

(1).对于增删改查,Collection中的共性方法

   方法说明:boolean add(Object obj);
             对于这个方法,是继承与Collection的,所以接收参数类型为Object类的比较合理,这个才可包容一切对象。

(2). 遍历用迭代器

     Student  stu=(Studeng)it.iterator();
     使用迭代器遍历对象时,必须进行强转,因为add()方法接收的是Object类,任何传入此方法中的类型都将得到提升,对象中的特性方法就不在具有,因此
想获取对象内部信息,就得强转,否则,多态编译失败。

 (3).去除重复元素

     boolean Contains(Object obj);
    方法原理:这个方法用来判断一个集合中是否包含特定对象,其底层依赖的是equals()方法,即通过对象的地址值比较两个对象是否相等,所以就要注意了,当你new 的
     对象用add()添加时,对象都不相等,所以就不能去除,对此,我们可以覆盖我们自定义对象中的equals方法,指定比较的对象成员属性,当有多个属性时,
先比主要的,在比次要的。

 (4).存储原理

   底层数据结构是数组,数组是固定长度的,但是集合长度是要求可以改变的,所以JAVA
   采用了一种可变长度数组机制,new ArrayList()首先构造一个初始容量为 10 的空列 
   表,之后若空间不够,就会new一个新的数组,长度以50%延长,也就是变成15,再把
   原来老数组中的元素copy进来,而Vector是以100%延长,所以ArrayList更节省空间
   这也是Vector被淘汰的一个原因。除此,Vector是同步的,所以在多线程操作增删查
   改的时候容易出现问题,而ArrayList是不同步的。

 (5).ArrayList、Vector与LinkedList的比较。

   从底层存储方式入手,ArrayList是基于数组的,LinkedList是基于链表的,所以对于ArrayList,查询速度很快,但是增删稍慢。线程不安全,效率高。
   对应的LinkedList增删速度很快,而查询速度稍慢,线程不安全,效率高。Vector底层数据结构是数组,查询快,增删慢。线程安全,效率低。这是选用容器的重要的衡量因素。

 (6).实例代码

 需求: 键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值

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);

		// 对数组排序
		// 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();
	}
}

4、Set的功能概述

  1.set特点

     元素无序(存入顺序与取出不一样),不可以重复(唯一性),其功能和collection 一样。

  2、理解的两个儿子 HashSet、TreeSet。

  2.1、HashSet的重要点介绍
    a.底层数据结构是哈希表,哈希表就是存放一堆哈希值的表,如果元素哈希值相等且内容不同,在同一位置往下顺延,如果不等则直接往后存储。当然如果哈希值相等,元素内容也一样,则就不能存进去。
    b.唯一性是如何保证的?
     HashSet的唯一性依赖两个它自动调用的方法,hashCode()和equals(),先比较对象的哈希值是否相等,如果相等,再调用equals(),如果值为true,就被踢出,不存入, 反之就存入。当然,       第一次调用hashCode()时返回的哈希值相等时,则再调用equals()。注意hashCode别写成hasCode。

    c.主要方法
     add(),clear(),contains(),size(),clone(),再加上迭代器的3个方法。contains()和remove()依赖的方法是hashCode和equals(),原理同上。
  

    d.示例代码
     需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。

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);
		}
	}
}

 2.2、TreeSet的重要点介绍
 a.排序的第一种方式:
   底层数据结构是二叉排序树,所以TreeSet可以对添加的对象进行自然排序,所以这就 要求我们添加的元素具有比较性,想要元素具有比较性,那就得实现Comparable接口并覆盖其compareTo()方法,这个方法自动被调用,让对象强制具有比较性,如果不实现将会抛出 ClassCastException异常,JAVA中很多类都已经实现了Comparable接 口,比如String实现Comparable后的compareTo方法就按照字母顺序来排序,但是  当我们自定义对象时,那就必须实现Comparable接口了。 
 b.排序的第二种方式:
  排序依据:如果元素不具有比较性或者具备的比较性不是所需要的时,可以使集合自身 具有比较性,在集合初始化时就具有了比较方式,所以这需要参与构造函数,定义比较  器,将比较器的对象传给TreeSet的构造函数。  备注:当两种排序方式都具备时,以比较器的方法为准
 c.比较器代码演示:
class Mycomp implements Comparator
{
	public int compare(Object o1, Object o2) {
		String s1=(String)o1;
		String s2=(String)o2;
		int num=s1.length()-s2.length();
		if(num==0)
		{
			num=s1.compareTo(s2);
		}
		return num;
	}
}
TreeSet ts=new TreeSet(new  Mycomp());
d.实例代码
需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
备注:学生类在此省去

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英语成绩");
		// 遍历集合
		for (Student s : ts) {
			System.out.println(s.getName() + "\t" + s.getChinese() + "\t"
					+ s.getMath() + "\t" + s.getEnglish());
		}
	}
}

5、Map的功能概述

(1).public interface Map<K,V>

此集合存入的是关系,一对一对的,键值对应将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。


(2).主要方法介绍:

   V put(K key ,V value)
   添加元素对,如果是基于哈希表结构的,新值会覆盖旧值,并返回旧值
   V remove ( Object key )
   通过键,返回值,并从集合中移除
   V get (Object key )
   通过键,获取值,可以看出这有局限,每次只能取一个值
   boolean containsKey( Object key )
   通过键,判断是否包含值
   Clooection <V> values()
   取出集合中所有的值,存进Collection之中


(3).Map集合最重要的两个方法,即取出方法。

   
a、第一种:set<K>  Keyset()从JDK文档看到,Map集合并没有迭代器,因为迭代器针对的是单例集合,而Map是一个双例集合,那么它的元素对是怎样被取出的呢?所以JAVA就想到了前者转化成后者,此时。
我们可以通过下面两个之中的任何一个方法。
set<K>  Keyset()
返回Map集合的所有键,并存入到set集合中,再用迭代器的方法遍历集合, 同时用V V get(Object key),得到集合里面的值。 
代码演示:

Map<String,String> m=new HashMap<String,String>();
m.put("1", "zhangsan1");。。。。。。
Set<String> keySet=m.keySet();
		//对键值集合进行遍历
	for(Iterator<String> it=keySet.iterator();it.hasNext();)
	{
		String str=it.next();
		System.out.print(str+"   ");
		String s=m.get(str);
		System.out.println(s);
	}
b、第二种:set<map.Entry<K,V>> entrySet ()
把Map集合中的映射关系存入到set集合之中,对于这种映射关系,我们可以把它哦也看成一种数据类型,而这个类型就是map.Entry,只是这种数据类型很猛,保存的是数据关系。而对set所呈现的仍是一个类型。
代码演示:

Map<String,String> m=new HashMap<String,String>();
m.put("1", "zhangsan1");。。。。。。
set<map.Entry<String,String>> =map.entrySet();
Iterator<map.Entry<String,String>> it =m.itraror();
while(it.hasNext())
{
   <map.Entry<String,String>> me=it.next();
   String s1=me.getKey();
   String s2=me.getValue();
   … … … … …
}

(4)HashMap嵌套HashMap

一所大学有多个学院,一个学院有多个专业,专业实体类包括两个属性,专业名称,该专业的学费,示例代码如下

public class HashMapDemo {
	public static void main(String[] args) {
		// 创建学校集合对象
		HashMap<String, HashMap<String, Integer>> universityMap = new HashMap<String, HashMap<String, Integer>>();

		// 创建软件学院集合对象
		HashMap<String, Integer> softCollegeMap = new HashMap<String, Integer>();
		// 添加元素
		softCollegeMap.put("软件工程", 10000);
		softCollegeMap.put("信息与计算科学",5000);
		// 把基础班添加到大集合
		universityMap.put("softCollegeMap", softCollegeMap);

		// 创建外语学院集合对象
		HashMap<String, Integer> foreignMap = new HashMap<String, Integer>();
		// 添加元素
		foreignMap.put("英语", 4500);
		foreignMap.put("日语", 4500);
		// 把外语学院添加到大集合
		universityMap.put("foreignMap", foreignMap);
		
		//遍历集合
		Set<String> universitySet = universityMap.keySet();
		for(String universitySetMapKey : universitySet){
			System.out.println(universitySetMapKey);
			HashMap<String, Integer> universityMapValue = universityMap.get(universitySetMapKey);
			Set<String> universityMapValueMapValueSet = universityMapValue.keySet();
			for(String universityValueKey : universityMapValueMapValueSet){
				Integer czbkMapValueValue = universityMapValue.get(universityValueKey);
				System.out.println("\t"+universityValueKey+"---"+czbkMapValueValue);
			}
		}
	}
}

6、Hashtable简单示例

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);
	}
}
最后:花费了一天的时间将集合的内容简单的回顾了一下,集合在JAVA编程中的作用之大无可厚非,无论是写服务端的项目还是Android端的项目,集合都一直陪伴着我们,所以集合的体系结构一定要熟悉,在什么情况下选用什么集合要清楚,好啦,今晚就到这里。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值