黑马程序员——013——JavaAPI⑤(集合框架(Map)、Collections)
来源:互联网 发布:linux下编译c程序 编辑:程序博客网 时间:2024/05/20 19:49
Map集合
我们在回头来看看我们Java集合类关系图:
左中部分已经基本被我们学习完了,现在轮到右边了。
这一节我们学习Map集合,Collection和Map都可以算是集合当中的顶层接口:
—他们外观没联系,实际上内部还是有联系的。
—Map下面也有一些子类对象,我们查看API文档;
——发现它的泛型看起来很叼的样子;K→key键,V→value值;
——k和v之间有映射关系;一个键映射一个值域;
—Map集合:该集合存储键值对,一对一对的往里面存的。因此我们知道需要保证键的唯一性。
—相较于ArrayList的加索引index,map就相当于起名字;
—因此我们可以形象的想象为:Collection是单列的,Map是双列的;
—Map集合的方法:
——①添加
———V put(K key, V value)
————将指定的值与此映射中的指定键关联(可选操作)。
———void putAll(Map
Map<String,String> map = new HashMap<String,String>();//——————————————————————//添加元素map.put("01","lisi1");map.put("02","lisi2");map.put("03","lisi3");//put方法在对旧键替换新值的时候,返回旧值,下第二句打印lisi1System.out.println(map.put("01","lisi2"));//打印"lisi1"//——————————————————————/*判断*///判断key存在System.out.println(map.containsKey("00"));//打印falseSystem.out.println(map.containsKey("01"));//打印true//判断value存在System.out.println(map.containsKey("lisi0"));//打印falseSystem.out.println(map.containsKey("lisi1"));//打印true//使用get方法,get(键)System.out.println(map.get("00")==true);//打印falseSystem.out.println(map.get("01")==true);//打印true//但是要注意,HashMap可以存空,因此不好用,不过一般谁也不会存空值吧:map.put("04",null);//存入控null值System.out.println(map.get("04"));//打印null//——————————————————————//获取map集合中所有的值。Collection<String> c = map.values();System.out.println(coll);System.out.println(map);
———————————————————————————
如果想要取出所有的键值,map集合的两种取出方式:
—①keySet方法;
——将map中所有的键存入到set集合。因为set具备迭代器。
——将所有可以迭代方式取出所有的键,在根据get方法,获取每一个键对应的值。
—②entrySet方法;将map集合的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry;
—我们用一个实例代码来演示两种取出方式的用法:
———————————————————————————
import java.util.*;class Demo13_1{ public static void main(String[] args) { /*通过keySet方法,获取map集合键值*/ func1(); /*通过entrySet方法,获取map集合键值*/ func2(); } /*通过keySet方法,获取map集合键值*/ static void func1() { Map<String,String> map = new HashMap<String,String>(); map.put("01","halo1"); map.put("02","halo2"); map.put("03","halo3"); map.put("04","halo4"); //仅获取map集合的所有键的Set集合,keySet() Set<String> keySet = map.keySet(); //有了键的set集合,就可以遍历获取到键值了 Iterator<String> it = keySet.iterator(); while(it.hasNext()) { //获取键值 String key = it.next(); //键值获取到了就可以通过它使用get方法获取值了 String value = map.get(key); System.out.println("key:"+key+"...value:"+value); } } /*通过entrySet方法,获取map集合键值*/ static void func2() { Map<String,String> map = new HashMap<String,String>(); map.put("01","halo1"); map.put("02","halo2"); map.put("03","halo3"); map.put("04","halo4"); 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(); //通过Map.Entry的getKey方法和getValue方法获取键值 String key = me.getKey(); String value = me.getValue(); System.out.println(key+":"+value); } }}
———————————————————————————
因此我们可以总结:
—Map集合的取出原理,将Map集合转成set集合,在通过迭代器取出;
——①keySet方法;
———将map中所有的键存入到set集合。因为set具备迭代器。
———将所有可以迭代方式取出所有的键,在根据get方法,获取每一个键对应的值。
——②entrySet方法;将map集合的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry;
——Map.Entry:其实Entry和Map一样,也是一个接口,它是Map接口中的一个内部接口;
——因此,先有Map集合才有Entry关系→内部类
——我们从API文档出也能看出来了,因为只有在内部类才能使用static修饰,如下图:
因此我们可以想到,源代码中一定存在以下代码逻辑:
———————————————————————————
/*接口Map源代码*/interface Map{ ...... public static interface Entry//等待被实现的Entry接口 { ...... public abstract Object getKey(); public abstract Object getValue(); ...... } ......}/*哈希Map源代码*/class HashMap implements Map{ ...... class Hahs implements Map.Entry//实现接口 { ...... //实现接口方法 public Object getKey(){...} public Object getValue(){...} ...... } ......}
———————————————————————————
我们使用下面的代码来演示Map集合的使用:
需求:每一个学生都有对应的归属地,学生Student,地址String;姓名和年龄相同则视为同一个学生,要保证学生的唯一性;
思路:
—①描述学生;
—②定义Map容器,将学生作为键,地址作为值,存入;
—③获取Map集合中的元素;
———————————————————————————
import java.util.*;class Demo13_2{ public static void main(String[] args) { HashMap<Student,String> hm = new HashMap<Student,String>(); hm.put(new Student("halo04",33),"xinjiang"); hm.put(new Student("halo02",53),"beijing"); hm.put(new Student("halo03",22),"guangdong"); hm.put(new Student("halo01",24),"haerbin"); //hm.put(new Student("halo03",22),"wuhan"); //第一种遍历HashMap方法使用keySet方法 Set<Student> keySet = hm.keySet(); Iterator<Student> it_keySet = keySet.iterator(); while(it_keySet.hasNext()) { Student s = it_keySet.next(); String addr = hm.get(s); System.out.println(s+".."+addr); } System.out.println("---------------"); //第二种遍历HashMap方法使用entrySet方法 Set<Map.Entry<Student,String>> entrySet = hm.entrySet(); Iterator<Map.Entry<Student,String>> it_entry = entrySet.iterator(); while(it_entry.hasNext()) { Map.Entry<Student,String> entry = it_entry.next(); Student s = entry.getKey(); String addr = entry.getValue(); System.out.println(s+".."+addr); } }}/*定义学生类,实现Comparable接口,让其具备比较性;*/class Student extends Person implements Comparable<Person>{ private String name; private int age; public Student(String name,int age) { this.name = name; this.age = age; } //覆盖equals方法 public boolean equals(Object obj) { if(!(obj instanceof Student)) throw new ClassCastException("类型不匹配!"); Student s = (Student)obj; return this.name.equals(s.getName()) && this.age == (s.getAge()); } //覆盖hashCode方法 public int hashCode() { return this.name.hashCode()+this.age*27; } //实现接口的compareTo方法 public int compareTo(Person p) {//Comparable接口,为了防止有需求要往二叉树里面存 if(!(p instanceof Student)) throw new ClassCastException("类型不匹配!"); int result = this.name.compareTo(p.getName()); if(result==0) { if(this.age>p.getAge()) return 1; else if(this.age==p.getAge()) return 0; return -1; } return result; } //覆盖toString方法 public String toString() { return name+":"+age; }}/*定义人类*/class Person{ private String name; private int age; public String getName() { return this.name; } public int getAge() { return this.age; }}
———————————————————————————
执行结果:
经验:一个类的对象可能涉及多种存储的时候,最好最好是↓
—①实现Comparable接口,实现compareTo方法,让对象天生可比性、可排序;
—②重写hashCode方法以及equals方法,保证对象能够往哈希表里面放;
———————————————————————————
我们再用一个实例演示TreeMap的使用:
需求:对上例中的学生对象进行按年龄升序排序;
思路:因为数据是以键值对形式存在的,一个学生对象对应一个地址,因此我们不能够使用List或者Set的单列集合,必须使用Map,然后又知道是需要排序的,因此我们就使用TreeSet;
———————————————————————————
import java.util.*;class Demo13_3{ public static void main(String[] args) { Map<Student,String> map = new TreeMap<Student,String>(new StudentComparator()); map.put(new Student("halo1",23),"哈尔滨"); map.put(new Student("halo2",21),"北京"); map.put(new Student("halo3",10),"广东"); map.put(new Student("halo4",21),"湖南"); map.put(new Student("halo1",10),"广东"); //使用entrySet方法获取键值 Set<Map.Entry<Student,String>> entrySet = map.entrySet(); Iterator<Map.Entry<Student,String>> it = entrySet.iterator(); while(it.hasNext()) { Map.Entry<Student,String> entry = it.next(); Student s = entry.getKey(); String addr = entry.getValue(); System.out.println(s+"--"+addr); } }}/*由于学生类中的排序方式不是我们想要的,那么,我们需要按照一个新的规则来排序,因此,如TreeSet一样,我们可以使用比较器*/class StudentComparator implements Comparator<Person>{ public int compare(Person p1,Person p2) { //如果不是学生的实例对象,抛RuntimeException的子类ClassCastException if(!(p1 instanceof Student)) { throw new ClassCastException("类型不匹配!请传入一个学生类的实例"); } if(!(p2 instanceof Student)) { throw new ClassCastException("类型不匹配!请传入一个学生类的实例"); } Integer age1 = new Integer(p1.getAge()); Integer age2 = new Integer(p2.getAge()); int compareResult = age1.compareTo(age2); if(compareResult == 0) { return p1.getName().compareTo(p2.getName()); } return compareResult; }}/*定义学生类,实现Comparable接口,让其具备比较性;*/class Student extends Person implements Comparable<Person>{ private String name; private int age; public Student(String name,int age) { super(name,age); this.name = name; this.age = age; } //覆盖equals方法 public boolean equals(Object obj) { if(!(obj instanceof Student)) throw new ClassCastException("类型不匹配!"); Student s = (Student)obj; return this.name.equals(s.getName()) && this.age == (s.getAge()); } //覆盖hashCode方法 public int hashCode() { return this.name.hashCode()+this.age*27; } //实现接口的compareTo方法 public int compareTo(Person p) {//Comparable接口,为了防止有需求要往二叉树里面存 if(!(p instanceof Student)) throw new ClassCastException("类型不匹配!"); int result = this.name.compareTo(p.getName()); if(result==0) { if(this.age>p.getAge()) return 1; else if(this.age==p.getAge()) return 0; return -1; } return result; } //覆盖toString方法 public String toString() { return name+":"+age; }}/*定义人类*/class Person{ private String name; private int age; public Person(String name,int age) { this.name = name; this.age = age; } public String getName() { return this.name; } public int getAge() { return this.age; }}
———————————————————————————
我们再来看一个TreeSet的练习:
需求:“sdfgz/-/-xcva#
—打印结果如“a(次数)b(次数)c(次数)…”abc按顺序的格式;
分析:每一个字母对应一个次数,因此,这个练习中的字母和对象是有映射关系的,因此我们使用Map集合,而又有需要打印结果按照abcd…顺序,因此需要排序,又有键值对有需要排序,不用多想,就是用TreeSet集合,看代码:
———————————————————————————
import java.util.*;class Demo13_4{ public static void main(String[] args) { String s = "sdfgz/*-/*-xcva#$%sdfxcv@#$!@df"; //对字母一个个操作,因此首先转成char数组 char[] chs = s.toCharArray(); //建立一个Map容器, //char泛型要写成包装类Character //int也是,Integer Map<Character,Integer> map = new TreeMap<Character,Integer>(); //循环判断每一个chs的元素 for(int i=0;i<chs.length;i++) { //当不是英文字母的时候,跳过这次循环 if(!((chs[i]<='z'&&chs[i]>='a') || (chs[i]<='Z'&&chs[i]>='A'))) continue; Integer value = map.get(chs[i]); if(value==null) value = 0; map.put(chs[i],value + 1); } //按照格式打印出结果 Set<Map.Entry<Character,Integer>> set= map.entrySet(); Iterator<Map.Entry<Character,Integer>> it = set.iterator(); while(it.hasNext()) { Map.Entry<Character,Integer> entry = it.next(); Character c = entry.getKey(); Integer i = entry.getValue(); System.out.print(c+"("+i+")"); } //打印结果:a(1)c(2)d(3)f(3)g(1)s(2)v(2)x(2)z(1) }}
———————————————————————————
打印结果:a(1)c(2)d(3)f(3)g(1)s(2)v(2)x(2)z(1)
———————————————————————————
Map扩展
Map集合被使用是因为具备映射关系;
—比如说一个学校,有很多教室,一间教室有很多学生一样;
—这时候就可以这么定义集合:
——首先是学校:
———Map
import java.util.*;class Demo13_5{ public static void main(String[] args) { //定义String对象的List集合容器 List<String> list = new ArrayList<String>(); list.add("dcca"); list.add("bcafwa"); list.add("akkkk"); list.add("yyyy"); list.add("aca"); list.add("z"); sop(list);//[dcca, bcafwa, akkkk, yyyy, aca, z] //1.按照字母自然顺序排序 //由于了String天生实现了Comparable接口 Collections.sort(list);//因此可以直接将集合传进来,不用使用sort两个参数的方法 sop(list);//[aca, akkkk, bcafwa, dcca, yyyy, z] //2.按照字母长度排序 //需要用到比较器了 list.add("aba");//添加多一个为了验证同等长度再按照字母自然顺序排 Collections.sort(list,new StringLengtComparator()); sop(list);//[z, aba, aca, dcca, yyyy, akkkk, bcafwa] } public static void sop(Object obj) { System.out.println(obj); }}/*按照字母长度排序的规则比较器*/class StringLengtComparator implements Comparator<String>{ public int compare(String s1,String s2) { int result = new Integer(s1.length()).compareTo(new Integer(s2.length())); if(result==0) return s1.compareTo(s2); return result; }}
———————————————————————————
Collections之max方法
—返回List集合中自然顺序排序的最后的一个元素;
—或者返回List集合中比较器顺序排序的最后的一个元素;
此方法我们看一个实例就能够明白其作用了:
——————————————————————
import java.util.*;class Demo13_6{ public static void main(String[] args) { //定义String对象的List集合容器 List<String> list = new ArrayList<String>(); list.add("dcca"); list.add("bcafwa"); list.add("akkkk"); list.add("yyyy"); list.add("zz"); list.add("aca"); list.add("z"); //不使用比较器 String max = Collections.max(list); sop(max);//打印自然顺序最大的串 zz //使用比较器 String lengthMax = Collections.max(list,new StringLengtComparator()); sop(lengthMax);//打印长度最大的串 bcafwa } public static void sop(Object obj) { System.out.println(obj); }}/*按照字母长度排序的规则比较器,略,同上例代码*/
———————————————————————————
Collections之binarySearch方法
binarySearch方法:使用二分法搜索指定List集合。
—当然也是有两个方法,一个不用比较器,一个用比较器:
——static int binarySearch(List
import java.util.*;class Demo13_7{ public static void main(String[] args) { //定义String对象的List集合容器 List<String> list = new ArrayList<String>(); list.add("dcca"); list.add("bcafwa"); list.add("akkkk"); list.add("yyyy"); list.add("zz"); list.add("aca"); list.add("z"); //按照自然顺序排序后查找 Collections.sort(list); sop(list);//查看排序后结果 //使用自写的二分法查找baa串 int index = halfSearch(list,"baa"); sop("自写的index="+index);//3 //使用官方提供的二分法查找baa串 index = Collections.binarySearch(list,"baa"); sop("官方的index="+index);//3 //按照长度排序后查找 Collections.sort(list,new StringLengtComparator()); sop(list);//查看按照长度排序后结果 //使用自写的二分法查找baa串 index = halfSearch2(list,"baa",new StringLengtComparator()); sop("自写的index="+index); //使用官方提供的二分法查找baa串 index = Collections.binarySearch(list,"baa",new StringLengtComparator()); sop("官方的index="+index); } public static void sop(Object obj) { System.out.println(obj); } /*自写的使用比较器的二分法查找*/ public static int halfSearch2(List<String> list,String key,Comparator<String> comp) { int max,min,mid=0; max = list.size()-1;min = 0; while(max>=min)// { mid = (max+min)>>1;//右移n位相当于除以2的n次方 String midStr = list.get(mid); int result = comp.compare(key,midStr); if(result>0) min = mid+1; else if(result<0) max = mid-1; else return mid; } return -min-1; //这里的返回值既要能够表现出找不到 //也能够表现出其能够插入的位置 //因此设置成 (-(插入点) - 1)。 } /*自写的不使用比较器的二分法查找*/ public static int halfSearch(List<String> list,String key) { int max,min,mid=0; max = list.size()-1;min = 0; while(max>=min)// { mid = (max+min)>>1;//右移n位相当于除以2的n次方 String midStr = list.get(mid); int result = key.compareTo(midStr); if(result>0) min = mid+1; else if(result<0) max = mid-1; else return mid; } return -min-1; //这里的返回值既要能够表现出找不到 //也能够表现出其能够插入的位置 //因此设置成 (-(插入点) - 1)。 }}/*按照字母长度排序的规则比较器,略,同上上例代码*/
———————————————————————————
理解代码的最关键部位就是理解为什么min是如果没有找到的时候最终的插入点。
—可以用一个实即的数字实例来画一下,就很好理解了;
———————————————————————————
Collections之fill方法
使用指定元素替换指定列表中的所有元素。
—不用多说,一个实例代码就能够说明问题:
———————————————————————————
import java.util.*;class Demo13_8{ public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("abcd"); list.add("aaa"); list.add("ccc"); list.add("zz"); list.add("kkk"); System.out.println(list); //将集合中的元素全部换成"halo" Collections.fill(list,"halo"); System.out.println(list); }}
———————————————————————————
执行结果:
思考:如果只要某一段元素需要替换怎么办?
———————————————————————————
Collection之replaceAll方法
replaceAll的API描述:
—public static boolean replaceAll(List list, T oldVal, T newVal)
——将list集合的oldVal替换成newVal;
实例代码:
———————————————————————————
import java.util.*;class Demo13_9{ public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("abcd"); list.add("aaa"); list.add("ccc"); list.add("zz"); list.add("kkk"); System.out.println(list); //将集合中的元素全部换成"halo" Collections.replaceAll(list,"aaa","halo"); System.out.println(list); }}
———————————————————————————
———————————————————————————
Collection之reverse方法
根据单词我们就知道是反转的意思了,实例代码:
———————————————————————————
import java.util.*;class Demo13_10{ public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("abcd"); list.add("aaa"); list.add("ccc"); list.add("zz"); list.add("kkk"); System.out.println(list); //将集合中的元素全部换成"halo" Collections.reverse(list); System.out.println(list); }}
———————————————————————————
执行结果:
———————————————————————————
Collections之reverseOrder方法
有两个:
—①空参数方法,能够提供一个针对自然顺序反序排序,也就是返回一个倒序排序的比较器;
—②重载方法,有一个参数,能够传入一个比较器作为参数,并且按照比较器的顺序,返回一个倒序排序的比较器;
实例代码:
———————————————————————————
import java.util.*;class Demo13_11{ public static void main(String[] args) { //按照字母自然顺序排序的TreeSet集合 //TreeSet<String> set // = new TreeSet<String>(); //按照字母自然顺序倒序排序的TreeSet集合 //TreeSet<String> set // = new TreeSet<String>(Collections.reverseOrder()); //按照字母长度顺序倒序排序的TreeSet集合 TreeSet<String> set = new TreeSet<String>(Collections.reverseOrder(new StringLengthComparator())); set.add("hasdfa"); set.add("dfwadfa"); set.add("a"); set.add("haa"); set.add("hasa"); sop(set); } public static void sop(Object obj) { System.out.println(obj); }}/*按照字母长度排序的规则比较器,略,上面已经写过了*/
———————————————————————————
Collections之synchronizedList方法
集合中那么多对象都是线程不安全的,那么如果多线程操作如何呢?
—Collections这个工具类就能够提供“给我不安全集合,返回你安全集合”的方法;
—————————————————————
—————————————————————
我们如果查看源码:可以发现其添加和删除方法都使用了同步代码块,加了同一个锁”mutex”:
所以结论就是:Collections中的方法能够让集合从非同步变成同步;
———————————————————————————
Collections之swap、reverse和shuffle方法
swap方法:可以替换list集合中的两个位置的元素:
—static void swap(List
- 黑马程序员——013——JavaAPI⑤(集合框架(Map)、Collections)
- 黑马程序员——Java语言基础:集合框架(Collection、Map,工具类Collections、Arrays)
- 黑马程序员——Java集合框架(三)之Map集合、Collections与Arrays工具类
- 黑马程序员——第五章 JavaAPI之集合框架
- 黑马程序员--集合框架(map集合,Collections,Arrays)
- 黑马程序员—collections集合
- 黑马程序员—collections集合
- 黑马程序员——Java基础—集合(Map、Collections)
- 黑马程序员——集合、集合框架工具类(collections和Arrays)和其他对象
- 黑马程序员——集合框架(Map详解)
- 黑马程序员——集合框架(Map)
- 黑马程序员——集合框架Map
- 黑马程序员——010——JavaAPI②(集合框架(List之ArrayList)、迭代器、枚举)
- 黑马程序员——011——JavaAPI③(集合框架(List之LinkedList)、(Set之HashSet)
- 黑马程序员——集合框架类(Collections、Arrays)
- 黑马程序员——java第十七天:集合框架(Collections和其他对象)
- 黑马程序员——Java基础---集合框架(二)及工具类Collections、Arrays
- 黑马程序员——集合(二)--Collections、Arrays、泛型
- 杭电 1248 寒冰王座(flyod)
- HDU 1864 最大报销额
- [hive]InvalidObjectException(message:Role admin already exists.)
- Java反射机制(二)
- [读书笔记]crt静态链接注意模块间内存传递
- 黑马程序员——013——JavaAPI⑤(集合框架(Map)、Collections)
- 关于volley javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: 错误
- 楼教主的final总结----2009年ACM-ICPC——瑞典取双
- 002三大类库02_Collection
- JDBC:execute(),executeQuery()和executeUpdate()的用法与区别
- spring扫描注解工具类scan
- NSTimer知识点和倒计时的实现
- mac 下对apk进行重新签名
- 欢迎使用CSDN-markdown编辑器