java的集合框架
1, java类集的整个体系的组成和关系,以及各个接口,类的文字说明:
集合框架的特征:高性能,对动态数组,链接表,树和散列表的实现是高性能,允许不同类型的类集以相同的方式工作.它不受对象数组长度的限制
Collection:
-|:List 里面的内容是有序的(存入和取出的顺序一致),允许重复的内容,有索引,它扩充了Collection接口,拥有更多的方法
--|:ArrayList 内部是数组数据结构,查询速度快,不同步,判断元素是否存在,删除元素,底层用的是equals方法
--|:LinkedList 内部是链表数据结构,增删的速度快,也是不同步的
-|:Set 不能存放重复的内容,是无序的,
--|:HashSet 不能存放重复的元素,采用散列的储存方式,没有顺序,判断元素是否存在,删除元素,底层用的是equals和hashcode方法
--|:TreeSet 不能存放重复的元素,输出的数据是有序的
------------------------------------------------------------------------------------------------------------------
名称 | 数据结构 | 是否有序 | 是否同步(安全) | 特点 |
ArrayList | 数组 | 有序 | 不同步 | 按照索引查询速度快 |
LinkedList | 链表 | 有序 | 不同步 | 增删速度快 |
Vector | 数组 | 有序 | 同步 | 线程安全,按照索引查询速度快 |
TreeSet | 二叉树 | 无序(可以提供比较器) | 不同步 | 根据比较器自定义排序 |
HashSet | 哈希表 | 无序 | 不同步 | 按照内容查询速度快 |
-------------------------------------------------------------------------------------------------------------------
package cn.wjd.ArrayList; import java.util.ArrayList; import java.util.Iterator; import cn.wjd.bean.Person; public class ArrayListTest { public static void main(String[] args) { ArrayList a1 = new ArrayList(); a1.add(new Person("zhangsan1",21));//存自定义对象的时候,需要强转 a1.add(new Person("zhangsan2",22)); a1.add(new Person("zhangsan3",23)); a1.add(new Person("zhangsan4",24)); Iterator it = a1.iterator(); while (it.hasNext()) { // System.out.println(((Person) it.next()).getName()); 这段代码具有局限性,在循环中,一个对象调用2次方法,会出现异常 Person p = (Person) it.next();//解决方法,得到一个对象,然后使用对象进行调用方法 System.out.println(p.getName() +"-->" + p.getAge()); } } }
以上ArrayList代码中,两个注意点,我这边在ArrayList的容器中,加入的是自定义的对象,所以在输出数据的时候,一定要进行强制转换,强转得到对象,输出对象内容,这两个步骤一定要分开走,否则假如是一步走的话在while循环的输出会出现异常.
由以上代码,引出集合的标准输出的方法,Iterator(迭代输出,使用最多的输出方式)和ListIterator(专门用于输出List中的内容).
2, 在ArrayList的集合中去掉重复的元素,同理还有另外一个需求,去掉一个数组中重复的元素,请看下面的代码
去掉集合中的重复元素
package cn.arraylist; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; public class ArrayList02 { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("a"); list.add("a"); list.add("b"); list.add("b"); list.add("c"); list.add("c"); List<String> li = getSingleElement(list); System.out.println(li); } public static List<String> getSingleElement(List<String> list) { ArrayList<String> temp = new ArrayList<String>(); ListIterator<String> it = list.listIterator(); while(it.hasNext()){ String str = it.next(); if(!temp.contains(str)) temp.add(str); } return temp; } }
去掉数组中的重复元素
package cn.demo; import java.util.ArrayList; import java.util.List; //数组去重复,例如: 原始数组是{4,2,4,6,1,2,4,7,8},得到结果{4,2,6,1,7,8} public class Demo2 { public static void main(String[] args) { int[] arr = {4,2,4,6,1,2,4,7,8}; List<Integer> list = new ArrayList<Integer>(); for(int i : arr){ if(!list.contains(i)) list.add(i); } System.out.print(list);
其实上面两段代码,使用到的思路是一样的,给定一个集合或者数组的时候,我们要改变它的长度,这个肯定是要考虑到用集合去解决的,因为数据的长度是不可以改变的,所以都得定义一个集合变量,来存储最后不重复的元素.
在去掉数组中重复元素的话,还有一个更加牛逼的方法,先将数组遍历装到ArrayList集合中(就算是int型的数组,它会自动变成Integer),然后把ArrayList这个数组中的元素全部添加到HashSet集合中去,由于HashSet的特点,所以直接去掉了重复元素,不过最后打印的数据的排列顺序会有点变化.你懂的.
package cn.demo; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Set; //数组去重复,例如: 原始数组是{4,2,4,6,1,2,4,7,8},得到结果{4,2,6,1,7,8} public class Demo01 { public static void main(String[] args) { int[] arr = {4,2,4,6,1,2,4,7,8}; List<Integer> al = new ArrayList<Integer>(); for(int i : arr){ al.add(i); } Set<Integer> set = new HashSet<Integer>(); set.addAll(al); System.out.println(set); } }
迭代输出:Iterator(迭代含义:一个个对集合中的内容进行判断,有内容就将其取出)
最标准的做法,只要碰到集合输出,一定要想到这个接口.标准输出代码如下:
Iterator it = col.iterator(); //Collection中的方法,返回Iterator对象 while(it.hasNext()){ //Iterator对象进行迭代判断,是否有下一个值 System.out.println(it.next());// 挨个取出当前元素 }
双向迭代输出:ListIterator(List专用的,只能通过List接口实例化,只能输出List接口中的内容)
package cn.wjd.List; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; public class ListDemo02 { public static void main(String[] args) { List list = new ArrayList(); //show(list); list.add("abc1"); list.add("abc2"); list.add("abc3"); System.out.println("原来的-->" + list); ListIterator it = list.listIterator(); //获取列表迭代器对象,它在迭代的过程中,可以完成对元素的增删改查,这个是list集合特有的 while (it.hasNext()) { //使用列表迭代器,操作的对象是迭代器对象,不是集合对象 Object obj = it.next(); if(obj.equals("abc2")) it.add("abc4"); else System.out.println("next -->" + obj); } System.out.println("列表迭代器迭代之后的-->" + list); /* list.add("abc1"); list.add("abc2"); list.add("abc3"); Iterator it = list.iterator(); while (it.hasNext()) { Object obj = it.next(); //java.util.ConcurrentModificationException if(obj.equals("abc2"))//在进行迭代操作的时候,不能进行集合的操作,这样容易出现异常,如,迭代的话知道集合的元素个数, list.add("abc4");//再进行集合操作,元素个数会发现变化,这样就出现了异常 else //解决方法,使用ListIterator接口来完成 System.out.println("next -->" + obj); }*/ } public static void show(List list) { list.add("abc1"); list.add("abc2"); list.add("abc3"); list.add("abc4"); Iterator it = list.iterator(); while (it.hasNext()) { System.out.println("next-->" + it.next()); } //List中特有的取数的方法,get()方法 for (int i = 0; i < list.size(); i++) { System.out.println("get-->" + list.get(i)); } } }
在List中,有了该方法,它就存在一个特有的取数方式,利用for循环,循环次数为List集合对象的长度,然后通过该方法循环输出.
List集合只能使用ListIterator进行输出的原因(ConcurrentModificationException 异常出现的原因):我们在进行迭代操作的时候,如果集合的引用和迭代器对象同时来操作容器中的内容,通过集合获取到的对应的迭代器,然后对集合进行增删改查的操作,假如使用之前的Iterator迭代的话,这个接口中是没有增删改查的方法的,这个时候我们只能使用它的子接口ListIterator来完成输出,直接查阅API中ListIterator的内容就了然了.
------------------------------------------------------------------------------------------------------------------------------------------------
Set下面的小弟TreeSet它是如何实现有序排放的?
1:让元素具有自己的比较功能,实现Comparator接口,通过覆盖其compare(T o1,T o2)比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数的方法,来自己建立2个对象比较的准则
int compare(T o1,T o2)比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
package cn.wjd.treeset; import java.util.Iterator; import java.util.TreeSet; import cn.wjd.bean.Person; public class TreeSetDemo { public static void main(String[] args) { TreeSet ts = new TreeSet(new ComparatorByName());//构造方法中直接传入已经定义好的比较器对象 ts.add(new Person("zhangsan",22)); ts.add(new Person("zhangsan",21)); ts.add(new Person("bhangsan4",24)); ts.add(new Person("a3",22)); ts.add(new Person("dhangsan5",25)); Iterator it = ts.iterator(); while (it.hasNext()) { Person p = (Person)it.next(); System.out.println(p.getName() + "-->" + p.getAge()); } } package cn.wjd.treeset; import java.util.Comparator; import cn.wjd.bean.Person; public class ComparatorByName implements Comparator { public int compare(Object o1, Object o2) { Person p1 = (Person)o1; Person p2 = (Person)o2; int temp = p1.getName().compareTo(p2.getName());//compareTo是String类中的方法,按照字典的顺序比较2个字符串 return temp == 0?p1.getAge() - p2.getAge():temp; }//该自定义的比较器中,优先比较的是Person对象的姓名,然后再比较的是Person对象的年龄 }
小插曲,关于三目运算符的格式:表达式1?表达式2:表达式3; 当表达式1是true的时候,执行表达式2,false时,执行表达式3.
一般表达式1是关系运算符或者是逻辑运算符.
2,让元素自身据有比较的功能,定义类的时候,直接让它实现Comparable接口,同时复写它的compare(T o)方法
package cn.wjd.bean; public class Person implements Comparable { private String name; private int age; @Override public boolean equals(Object obj) { Person p = (Person)obj; return this.name.equals(p.name) && this.age == p.age ; } @Override public int hashCode() { return name.hashCode() + age; } public Person(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; } public int compareTo(Object o) { Person p = (Person)o; // int temp = this.age - p.age; // return temp == 0?this.name.compareTo(p.name):temp; int temp = this.name.compareTo(p.name); return temp == 0?this.age - p.age:temp; /*if(this.age > p.age) return 1; if(this.age < p.age) return -1; return 0;*/ } }
一般第一种方法灵活,在开发中,第一种使用的比较多
HashSet
它的底层数据结构是哈希表,线程不同步,无序,高效.
如何确定该集合中元素的唯一性?
是通过对象的hashcode和equals方法来完成对象的唯一性
如果对象的hashcode值不同,就不需要判断equals方法
如果对象的hashcode值相同,则需要判断equals方法,记住hashcode是第一步,equals是第二部
true,视为相同元素,false,视为不同元素
记住,元素要存储在HashSet中,必须要覆盖hashcode和equals方法
关于java中的哈希表
1,对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。
2,哈希值就是这个元素的位置。
3,如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。
4,存储哈希值的结构,我们称为哈希表。
5,既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。
----------------------------------------------------------------------------------------------------------------------------------------------
Map集合
Map集合中存储的是一对元素(key->value),key和value都有对应的映射关系,要保证Map集合中key的唯一性.
Map常用的子类
--|Hashtable:内部结构哈希表,是同步的。不允许null作为键,作为值
--|Properties类:用来存储键值对型配置文件的信息,可以和IO技术相结合
--|HashMap:内部结构是哈希表,不是同步的。允许null作为键,作为值
--|TreeMap:内部结构是二叉树,不同步,可以对Map中的键进行排序
Map.Entry接口简介
Map.Entry接口是Map内部定义的一个接口,专门用来保存key->value的内容,直白一点,在Map集合中插入的就是一个Map.Entry的实例化对象
----------------------------------------------------------------------------------------------------------------------------------------
集合 | 数据类型 | 是否有序 | 是否重复 | key允许null |
HashMap | 哈希表 | 无序 | 不允许重复 | 最多一个 |
TreeMap | 二叉树 |
有序 |
不允许重复 | 不允许 |
Hashtable | 哈斯表 | 无序 | 不允许重复 | 最多一个 |
----------------------------------------------------------------------------------------------------------------------------------------
Map集合的输出方式:
由于Map它没有自己的迭代器,所以在输出的时候,需要转化成Set集合,然后再进行迭代输出.
package cn.wjd.map; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class MapDemo { public static void main(String[] args) { Map<Integer,String> map = new HashMap<Integer, String>(); //method(map); method_2(map); } public static void method_2(Map<Integer, String> map) { map.put(2, "zhangsan2"); map.put(1, "zhangsan1"); map.put(3, "zhangsan3"); map.put(6, "zhangsan6"); map.put(5, "zhangsan5"); /*Map集合第一种取出方式 * 对Map集合进行输出,因为Map集合没有迭代器 * 1,通过Map集合中的keySet方法,来返回Map集合中的key元素的Set集合 * 2,使用Set集合中的迭代,对Map中的key进行迭代输出 * 3,使用Map中的get(key)方法,来取出Map中的所有元素内容 */ /*Set<Integer> keyset = map.keySet(); Iterator<Integer> it = keyset.iterator(); while (it.hasNext()) { Integer key = it.next(); String value = map.get(key); System.out.println(key + "-->" + value); }*/ /* * Map集合的第二种取出方法 * 也是通过Map转换成Set,进行迭代取出 * 使用Map中的entrySet方法,来返回包含映射关系的Set视图 * 再使用Map.EntrySet接口中的getKey和getValue方法,来取出Map中的元素 */ Set<Map.Entry<Integer, String>> entrySet = map.entrySet(); Iterator<Map.Entry<Integer, String>> it = entrySet.iterator(); while (it.hasNext()) { Map.Entry<Integer, String> me = it.next(); System.out.println(me.getKey() +"-->" +me.getValue()); } } public static void method(Map<Integer,String> map){ System.out.println(map.put(8, "zhangsan")); System.out.println(map.put(8, "lisi")); System.out.println(map); } }