一、map集合 Map:一次添加一对元素。Collection 一次添加一个元素。 Map也称为双列集合,Collection集合称为单列集合。 其实map集合中存储的就是键值对(结婚证书), map集合中必须保证键的唯一性。 方法简介: 1、添加 put(K key, V value) 以键值对的形式往里存 putAll(Map<? extends K,? extends V> m) 把一个map里的内容作为值存入进map中。 2、删除 clear() 清空集合 remove(Object key) 清楚其中的一条 3、判断 containsValue(Object value) 判断map中是否包含某个值 containsKey(Object key) 判断map中是否包含某个值 isEmpty()判空 4、获取 get(Object key) 根据key获取值 size() 获取map集合的大小
Set<Map.Entry<K,V>>返回键值对关系,并存放在Set集合中
注: a、也可以通过get()方法的返回值来判断一个键是否存在,通过返回null来判断。 b、其中put方法:如果出现添加相同的键,那么后添加的值会覆盖原有键对应的值,并且该方法返回被覆盖的值即原值。 class MapDemo { public static void main(String[] args) { Map<String,String> map = new HashMap<String,String>(); //添加元素,添加元素,如果出现添加时,相同的键,那么后添加的值会覆盖原有键对应值,并返回以前的值,以前没值就放回null System.out.println("put:"+map.put("01","zhangsan1")); System.out.println("put:"+map.put("01","wnagwu")); map.put("02","zhangsan2"); map.put("03","zhangsan3"); System.out.println("containsKey:"+map.containsKey("022")); 判断 //System.out.println("remove:"+map.remove("02"));删除 System.out.println("get:"+map.get("023")); map.put("04",null); System.out.println("get:"+map.get("04")); //可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断。 //获取map集合中所有的值。 Collection<String> coll = map.values(); System.out.println(coll); System.out.println(map); } 两种获取集合元素的方法: 1、keySet()方法获取元素 原理:将Map集合中的所有键存入到Set集合中,因为Set集合具备迭代器,所以可以用迭代方式取出所有的键,再根据get方法获取每一个键对应的值。简单说就是:Map集合---->Set集合 ---->迭代器取出
class MapDemo2 { public static void main(String[] args) { Map<String,String> map = new HashMap<String,String>(); // Map<Integer,String> map = new HashMap<Integer,String>(); // map.put(8,"zhaoliu"); map.put("02","zhangsan2"); map.put("03","zhangsan3"); map.put("01","zhangsan1"); map.put("04","zhangsan4"); //先获取map集合的所有键的Set集合,keySet(); Set<String> keySet (故意起的,有意义)= map.keySet(); //有了Set集合。就可以获取其迭代器。 Iterator<String> it = keySet.iterator(); while(it.hasNext()) { String key = it.next(); //有了键可以通过map集合的get方法获取其对应的值。 String value = map.get(key); System.out.println("key:"+key+",value:"+value); } } } 2、entrySet()方法获取元素: 原理:将Map集合中的映射关系存入到了Set集合中,而这个映射关系的数据类型是Map.Entry(结婚证),在通过迭代器将映射关系存入到Map.Entry集合中,并通过其中的getKey()和getValue()放取出键值。
class MapDemo2 { public static void main(String[] args) { Map<String,String> map = new HashMap<String,String>(); map.put("02","zhangsan2"); map.put("03","zhangsan3"); map.put("01","zhangsan1"); map.put("04","zhangsan4"); //将Map集合中的映射关系取出。存入到Set集合中。 Set<Map.Entry<String,String>> entrySet = map.entrySet(); Iterator<Map.Entry<String,String>> it = entrySet.iterator(); while(it.hasNext()) { Map.Entry<String,String> me = it.next(); String key = me.getKey(); String value = me.getValue(); System.out.println(key+":"+value); } } } 补充:关于<Map.Entry<String,String>> Map是一个接口,其实,Entry也是一个接口,它是Map的子接口中的一个内部接口,就相当于是类中有内部类一样。为何要定义在其内部呢? 原因: a.Map集合中存的是映射关系这样的两个数据,是先有Map这个集合,才可有映射关系的存在,而且此类关系是集合的内部事务。 b.并且这个映射关系可以直接访问Map集合中的内部成员,所以定义在内部。
3、只获取姓名,可以用下面得的,当然可以用上面的:
Map常用的子类: |--Hashtable :内部结构是哈希表,是同步的。不允许null作为键,null作为值。 //最先出来 |--Properties:用来存储键值对型的配置文件的信息,可以和IO技术相结合。 |--HashMap : 内部结构是哈希表,不是同步的。允许null作为键,null作为值。 |--TreeMap : 内部结构是二叉树,不是同步的。可以对Map集合中的键进行排序。 注:Set底层就是使用了Map集合。 演示1: public class HashMapDemo { public static void main(String[] args) { /* * 将学生对象和学生的归属地通过键与值存储到map集合中 */ HashMap<Student,String> hm = new HashMap<Student,String>(); hm.put(new Student("lisi",38),"北京"); hm.put(new Student("zhaoliu",24),"上海"); hm.put(new Student("xiaoqiang",31),"沈阳"); hm.put(new Student("wangcai",28),"大连"); hm.put(new Student("zhaoliu",24),"铁岭"); //覆盖了,需要在person类中重写hashcode和equals方法 // Set<Student> keySet = hm.keySet();// Iterator<Student> it = keySet.iterator(); 简写: Iterator<Student> it = hm.keySet().iterator(); while(it.hasNext()){ Student key = it.next(); String value = hm.get(key); System.out.println(key.getName()+":"+key.getAge()+"---"+value); } } } 演示2:排序 class ComparatorByName implements Comparator<Perosn> { public int compare(Person o1,Person o2){ int temp=o1.getName().comparaTo.(o2.getName); return temp==0? o1.getAge-o2.getAge:temp; } } public class TreeMapDemo { public static void main(String[] args) { TreeMap<Student,String> tm = new TreeMap<Student,String>(new ComparatorByName()); tm.put(new Student("lisi",38),"北京"); tm.put(new Student("zhaoliu",24),"上海"); tm.put(new Student("xiaoqiang",31),"沈阳"); tm.put(new Student("wangcai",28),"大连"); tm.put(new Student("zhaoliu",24),"铁岭"); Iterator<Map.Entry<Student, String>> it = tm.entrySet().iterator(); while(it.hasNext()){ Map.Entry<Student,String> me = it.next(); Student key = me.getKey(); String value = me.getValue(); System.out.println(key.getName()+":"+key.getAge()+"---"+value); } } } 演示3:LinkedHashMap(有序),和LinkedHashSet使用一样 public class LinkedHashMapDemo { public static void main(String[] args) { HashMap<Integer,String> hm = new LinkedHashMap<Integer,String>(); hm.put(7, "zhouqi"); hm.put(3, "zhangsan"); hm.put(1, "qianyi"); hm.put(5, "wangwu"); Iterator<Map.Entry<Integer,String>> it = hm.entrySet().iterator(); while(it.hasNext()){ Map.Entry<Integer,String> me = it.next(); Integer key = me.getKey(); String value = me.getValue(); System.out.println(key+":"+value); } }} 练习: 1 * "fdgavcbsacdfs" 获取该字符串中,每一个字母出现的次数。 * 要求打印结果是:a(2)b(1)...; * 思路: * 对于结果的分析发现,字母和次数之间存在着映射的关系。而且这种关系很多。 * 很多就需要存储,能存储映射关系的容器有数组和Map集合。 * 关系一方式有序编号吗?没有! * 那就是使用Map集合。 又发现可以保证唯一性的一方具备着顺序如 a b c ... * 所以可以使用TreeMap集合。 * * 这个集合最终应该存储的是字母和次数的对应关系。 * * 1,因为操作的是字符串中的字母,所以先将字符串变成字符数组。 * 2,遍历字符数组,用每一个字母作为键去查Map集合这个表。 * 如果该字母键不存在,就将该字母作为键 1作为值存储到map集合中。 * 如果该字母键存在,就将该字母键对应值取出并+1,在将该字母和+1后的值存储到map集合中, * 键相同值会覆盖。这样就记录住了该字母的次数. * 3,遍历结束,map集合就记录所有字母的出现的次数。 class MapTest1 { public static void main(String[] args) { String s= charCount("ak+abAf1c,dCkaAbc-defa"); //返回一个新的字符串结果 System.out.println(s); } public static String charCount(String str) { //将字符串变成字符数组 char[] chs = str.toCharArray(); //定义map集合表。 Map<Character,Integer> tm = new TreeMap<Character,Integer>(); //因为只存取,不需要TreeMap的特有方法,将他提升为map就可以 for(int x=0; x<chs.length; x++) { if(!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z')) continue; //将数组中的字母作为键去查map表。 Integer value = tm.get(chs[x]); //直接作为键去查表 int count = 1; //计数器 //判断值是否为null. if(value!=null){ count = value+1; //用个变量记录下 }// count++; map.put(chs[i], count); /* //这种比较麻烦 if(value==null){ map.put(chs[i], 1); }else{ map.put(chs[i], value+1); //直接往集合中存储字符和数字,为什么可以,因为自动装箱 } */ } } //System.out.println(tm); // 上边已经解决,转换它的那种结果a(2)b(1). return mapToString(map); } private static String mapToString(Map<Character, Integer> map) { StringBuilder sb = new StringBuilder(); Iterator<Character> it = map.keySet().iterator(); while(it.hasNext()){ Character key = it.next(); Integer value = map.get(key); sb.append(key+"("+value+")"); } return sb.toString(); }} 练习2: map什么时候用, Map在有映射关系时,可以优先考虑。在查表法中的应用较为多见。 public class MapTest2 { public static void main(String[] args) { String week = getWeek(1); //查表 System.out.println(week); System.out.println(getWeekByMap(week)); } public static String getWeekByMap(String week){ Map<String,String> map = new HashMap<String,String>(); map.put("星期一","Mon"); map.put("星期二","Tus"); map.put("星期三","Wes"); map.put("星期日","Sun"); map.put("星期天","Sun"); return map.get(week); } public static String getWeek(int week){ if(week<1 || week>7) throw new RuntimeException("没有对应的星期,请您重新输入"); String[] weeks = {"","星期一","星期二"}; return weeks[week]; }}
第二:Collections工具类
Collections和Collection有什么区别?
List:对元素都有定义索引。有序的。可以重复元素。 Set:不可以重复元素。无序。
提供的方法中有可以对list集合进行排序,二分查找等方法。 通常常用的集合都是线程不安全的。因为要提高效率。 如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的
工具类的Collections和Arrays中的方法全是静态的,下面主要总结几个比较重要的方法。
一、Collections工具类:在Collections工具类中很多方法是用于对集合进行操作的,如比较,查找,随机排序等等
1、查找:
T max(Collection<? extends T> coll) ---> 根据集合的自然顺序,获取coll集合中的最大元素
T max(Collection<? extends T> coll,Comparator<? super T> comp) ---> 根据指定比较器comp的顺序,获取coll集合中的最大元素
int binarySearch(Lsit<? extends Comparable<? super T>> list,Tkey) ---> 二分法搜索list集合中的指定对象
2、替换:
void fill(List<? super T> list, T obj) ---> 将list集合中的全部元素替换成指定对象obj
boolean replaceAll(List<T> lsit,T oldVal,T newVal) ---> 使用newVal替换list集合中的oldVal值
3、排序:
void shuffle(List<?> list) ---> 使用默认随机源对list集合中的元素进行随机排序
void sort(Lsit<T> list) ---> 根据自然顺序对list集合中的元素进行排序
void sort(List<T> lsit,Comparator<? super T> c) ---> 根据指定比较器c的排序方式对list集合进行排序
4、反转
reverse(List<?> list) ---> 反转list集合中元素的顺序
Comparator reverseOrder() ---> 返回一个比较器,强行逆转了实现Comparable接口的对象的自然顺序
Comparator reverseOrder(Comparator<T> cmp) ---> 返回一个比较器,强行逆转了指定比较器的顺序
演示方法:
public class CollectionsDemo { public static void main(String[] args) { demo_1(); }public static void demo_1(){ //排序 List<String> list = new ArrayList<String>(); list.add("abcde"); list.add("cba"); list.add("aa"); list.add("zzz"); list.add("cba"); list.add("nbaa"); System.out.println(list);//输出[abc, cbcef, ebcefgh, dbcefg, bbce],取出的时候用迭代器
对list集合重复元素进行指定顺序的排序。 有重复元素而且要指定顺序排序,就需要Collections
自然排序, 指定排序俩种比较方式,凡事设计比较的无外乎就是这俩种
// Collections.sort(list); 自然排序[abc, bbce, cbcef, dbcefg, ebcefgh]// mySort(list);// mySort(list,new ComparatorByLength()); Collections.sort(list,new ComparatorByLength()); 指定排序(简单) System.out.println(list); }
class ComparatorByLength implements Comparator<String> {//要新建这个类,写成内部类不行 @Override public int compare(String o1, String o2) { int temp = o1.length() - o2.length(); return temp == 0 ? o1.compareTo(o2) : temp; }}
源码: Collections.sort(list,new ComparatorByLength())的排序原理
public static <T> void mySort(List<T> list,Comparator<? super T> comp){ for (int i = 0; i < list.size()-1; i++) { for (int j = i+1; j < list.size(); j++) { if(comp.compare(list.get(i), list.get(j))>0){// T temp = list.get(i);// list.set(i, list.get(j));// list.set(j, temp); Collections.swap(list, i, j); } } }
源码: Collections.sort(list)的排序原理
public static <T extends Comparable<? super T>> void mySort(List<T> list){ 长度比较//<T extends Comparable<? super T>>需要限定,继承Comparable的才能比较,然后superT,T的子类和T都可以 for (int i = 0; i < list.size()-1; i++) { for (int j = i+1; j < list.size(); j++) { if(list.get(i).compareTo(list.get(j))>0){ Collections.swap(list, i, j); public static void demo_2(){二分查找、最值 List<String> list = new ArrayList<String>(); list.add("abcde"); list.add("cba"); list.add("aa"); list.add("zzz"); list.add("cba"); list.add("nbaa");// Collections.sort(list); 没顺序不能折半,先排序 System.out.println(list);
// int index = Collections.binarySearch(list, "cba");// System.out.println("index="+index); //获取最大值。 String max = Collections.max(list,new ComparatorByLength());//list,new ComparatorByLength()自然排序/排序器(名字长度)最值 demo_1 System.out.println("max="+max); }
逆序:
public static void demo_3() { /*用比较器逆序 TreeSet<String> ts = new TreeSet<String>(new Comparator<String>(){ public int compare(String o1, String o2) { int temp = o2.compareTo(o1); return temp; } }); */ TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder(new ComparatorByLength())); ts.add("abc"); ts.add("hahaha"); ts.add("zzz"); ts.add("aa"); ts.add("cba"); System.out.println(ts); }
替换
public static void demo_4() { List<String> list = new ArrayList<String>(); list.add("abcde"); list.add("cba"); list.add("zhangsan"); list.add("zhaoliu"); list.add("xiaoqiang");
System.out.println(list);
// Collections.replaceAll(list, "cba", "nba"); // set(indexOf("cba"),"nba"); 这是俩步,一样
新的没有枚举,转成老的
Collections.shuffle(list); (洗牌)// Collections.fill(list, "cc"); System.out.println(list); }
将非同步集合转成同步集合
加锁原理
List list = new ArrayList();//非同步的。list = MyCollections.synList(list);//返回一个同步的list. 给非同步的集合加锁。class MyCollections{ public static List synList(List list){ return new MyList(list); } private class MyList implements List{ private List list; private static final Object lock = new Object(); MyList(List list){ this.list = list; }在加元素的同时,删除元素 public boolean add(Object obj){ synchronized(lock) { return list.add(obj); } } public boolean remove(Object obj){ synchronized(lock) { return list.remove(obj); } }}
第三:Arrays工具类
Arrays:操作数组的工具
Collections:操作集合的工具
public class ArraysDemo {tic void main(String[] args) { /* * Arrays:集合框架的工具类。里面的方法都是静态的。 * */// int[] arr = {3,1,5,6,3,6};// System.out.println(Arrays.toString(arr)); 输出为[3,1,5,6,3,6] }//toString的经典实现。 public static String myToString(int[] a){ int iMax = a.length - 1; if (iMax == -1) return "[]"; StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; ; i++) {//中间省略条件判断,提高了效率。 b.append(a[i]); if (i == iMax) return b.append(']').toString(); b.append(", "); } }
public static void demo_1() { /* * 重点:List asList(数组)将数组转成集合。 * * 好处:其实可以使用集合的方法操作数组中的元素。 * 注意:数组的长度是固定的,所以对于集合的增删方法是不可以使用的 * 否则会发生UnsupportedOperationException * */ String[] arr = {"abc","haha","xixi"}; 以前:比较麻烦 boolean b = myContains(arr, "xixi"); System.out.println("contains:"+b); public static boolean myContains(String[] arr,String key){ for (int i = 0; i < arr.length; i++) { if(arr[i].equals(key)) return true; } return false; }
现在:
List<String> list = Arrays.asList(arr); boolean b1 = list.contains("xixi"); System.out.println("list contaisn:="+b1);// list.add("hiahia");//UnsupportedOperationException System.out.println(list); } public static void demo_2() { /* * 如果数组中的元素是对象,那么转成集合时,直接将数组中的元素作为集合中的元素进行集合存储。 * * 如果数组中的元素是基本类型数值,那么会将该数组作为集合中的元素进行存储。 * */ int(写成integer是对象)[] arr = {31,11,51,61}; List<int[]> list = Arrays.asList(arr); System.out.println(list); 这里的集合中只有一个元素 }
* 集合转成数组
*
* 使用的就是Collection接口中的toArray方法。
*
* 集合转成数组:可以对集合中的元素操作的方法进行限定。不允许对其进行增删。 变成数组就不能增删了,只能查阅
public class ToArray { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("abc1"); list.add("abc2"); list.add("abc3"); /* * toArray方法需要传入一个指定类型的数组。 * 长度该如何定义呢? * 如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同size的数组。 * 如果长度大于集合的size,那么该方法就会使用指定的数组,存储集合中的元素,其他位置默认为null。 * * 所以建议,最后长度就指定为,集合的size。 */ String[] arr = list.toArray(new String[list.size()]); //字符串数组 System.out.println(Arrays.toString(arr)); }}
一个ArrayList对象alist中存有若干个字符串元素,现欲遍历该ArrayList对象,
删除其中所有值为"abc"的字符串元素,请问下面的实现正确么?如有问题,
会出现什么问题?如何更正
int size = alist.size();for(int i = 0; i < size; i++) { if("abc".equals(alist.get(i))) { alist.remove(i); }}*/public class Test13 { public static void main(String[] args) { ArrayList<String> al = new ArrayList<String>(); al.add("haha"); al.add("abc"); al.add("abc"); al.add("abc");// int size = al.size(); for(int x=0; x<al.size(); x++){ if("abc".equals(al.get(x))){ al.remove(x); x--; } } System.out.println(al); }}