黑马程序员----------------java基础-----------------Map集合

来源:互联网 发布:微信交友源码 编辑:程序博客网 时间:2024/05/17 04:54


------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

第一讲 map集合概述


1、将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
 什么时候使用map集合呢?
 当数据之间存在这映射关系时,就要先想map集合。

2、基本方法
 
 2.1、put(K key, V value)
  
  如果出现添加相同的键时,那么后添加的值会覆盖原有键对应值、并且put方法会返回被覆盖的值。
  特点:保证键的唯一性
重要:
 向map集合中添加元素时,如果返回的是空,说明该键是第一次存入。
 
 2.2、、删除。
  
  clear()
  以前与 key 关联的值;如果没有 key 的映射关系,则返回 null
  并且remove方法会返回被删除的键对应的值。value remove(Object key)
 
 2.3、判断
  
  如何存在,则返回true,否则false
  boolean containsValue(Object value)
  boolean containsKey(Object key)
  boolean isEmpty()
 2.4、获取。
  
  指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null
  get(Object key) 得到键对应的值
  size() 得到集合长度
  entrySet() 返回此映射中包含的映射关系的 Set 视图。
  keySet() 返回此映射中包含的键的 Set 视图。

3、Map子类对象特点
 
  Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合 是线程同步的,必须实现hashCode和equals方法,jdk1.0,效率低。
  HashMap:底层是哈希表数据结构,允许一个null键和多个null值,该集合是不同步的。将hashtable替代,jdk1.2,效率高。也需要实现元素的hashCode 和equals方法。
  TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

4、Map集合的两种取出方式:
 
 4.1、keyset方式
  将map集合中所有的键值取出放到set集合,set集合可以利用迭代器取出每个键值,然后根据map集合的get方法取出每个键对应的值
 4.2、entrySet方式
  将map集合的一种映射关系存入set集合,这种关系就是Map.Entry。然后利用getkey()和getvalue()方法,分别取出键和值

说明:
 Map是一个接口,其实,Entry也是一个接口,它是Map的子接口中的一个内部接口,就相当于是类中有内部类一样。为何要定义在其内部呢?
   原因:a、Map集合中村的是映射关系这样的两个数据,是先有Map这个集合,才可有映射关系的存在,而且此类关系是集合的内部事务。
         b、并且这个映射关系可以直接访问Map集合中的内部成员,所以定义在内部。


import java.util.*;

//Map集合的两种取出方式


class  MapTest
{
 public static void main(String[] args)
 {
  Map <String,String>map=new HashMap<String,String>();//通过泛型定义要存入map集合的是字符串
  map.put("zhnagsan","20");
  map.put("wangwun","26");
  map.put("lisi","24");//向集合中添加元素
  map.put("zhnagqiang","22");
  //keyset方式练习
  Set<String > keyset=map.keySet();//用keyset方法将键存入set集合
  Iterator<String> it=keyset.iterator();//利用迭代器取出键值
  while (it.hasNext())
  {
   String key=it.next();
   String value=map.get(key);//用map的get方法取出键对应的值
   System.out.println(key+":::"+value);
  }

  
  //entryset方式练习
  Set<Map.Entry<String,String>> entryset=map.entrySet();//将map集合的一种映射关系存入set集合
  
  Iterator<Map.Entry<String,String>> newit=entryset.iterator();//利用迭代器取出键值
  while (newit.hasNext())
  {
   Map.Entry<String,String> me=newit.next();
   
   String key=me.getKey();//然后利用getkey()方法,取出键
   String value=me.getValue();//然后利用ggetvalue()方法,取出值
   System.out.println(key+":::"+value);
  }
  
 }
}

练习二  每一个学生都有对应的归属地,归属地用String表示,学生的属性有姓名、年龄,姓名和年龄相同
的学生认为是同一对象。要求保证元素唯一性。
*/


/*
分析:
1.创建学生类,对属性进行描述
2.学生有对应的归属地,有对应关系,存入map集合
3.要保证对象的唯一性,可以用hashmap集合,复写hashcode方法和equals方法

*/

/*
class Student
{
 private String name;
 private int age;
 Student(String name,int age)//创建构造函数
 {
  this.name=name;
  this.age=age;
 
 }
//复写hashcode方法,保证元素唯一性的依据是hashcode方法和equals
 public int hashCode()
 {
  return name.hashCode()+age*78;
 
 }
 public boolean equals(Object obj)
 {
  if(!(obj instanceof Student))
   throw new RuntimeException("类型不符");
  Student s=(Student)obj;
  return this.name.equals(s.name) && this.age==s.age;
 
 }
 public void setName(String name)//设置姓名的方法
 {
  this.name=name;
 
 }
 public String getName()//获取姓名的方法
 {
  return name;
 }
 public void setAge(int age)//设置年纪的方法
 {
 
  this.age=age;
  
 }
 public int getAge()//获取年纪的方法
 {
  return age;
 }
}

class  MapTest
{
 public static void main(String[] args)
 {

  HashMap<Student,String>hm=new HashMap<Student,String>();//加入泛型,明确存入的是学生对象
  hm.put(new Student("zhangsan",25),"beijing");
  hm.put(new Student("lisi",22),"nanjing");
  hm.put(new Student("zhaoliu",24),"tianjin");//添加自定义元素
  hm.put(new Student("zhangsan",25),"tianjin");
  
  Set<Student> keyset=hm.keySet();//用keyset方法将键存入set集合
  
  Iterator<Student> it=keyset.iterator();

   while (it.hasNext())//利用迭代器取出键值
   {
    Student s=it.next();
    String id=hm.get(s);//用map的get方法取出键对应的值
    System.out.println(s.getName()+s.getAge()+":::"+id);
   }
 }
}
*/

//每一个学生都有对应的归属地,归属地用String表示,学生的属性有姓名、年龄,将学生对象按年龄排序

/*
class Student implements Comparable <Student>
{
 private String name;
 private int age;
 Student(String name,int age)//创建构造函数
 {
  this.name=name;
  this.age=age;
 
 }
 public int compareTo(Student s)//复写compareTo方法
 {
  int num=new Integer(this.getAge()).compareTo(new Integer(s.getAge()));
  if(num==0)
   return this.getName().compareTo(s.getName());
  return num;
 
 }


//复写hashcode方法,保证元素唯一性的依据是hashcode方法和equals
 public int hashCode()
 {
  return name.hashCode()+age*78;
 
 }
 public boolean equals(Object obj)
 {
  if(!(obj instanceof Student))
   throw new RuntimeException("类型不符");
  Student s=(Student)obj;
  return this.name.equals(s.name) && this.age==s.age;
 
 }
 public void setName(String name)//设置姓名的方法
 {
  this.name=name;
 
 }
 public String getName()//获取姓名的方法
 {
  return name;
 }
 public void setAge(int age)//设置年纪的方法
 {
 
  this.age=age;
  
 }
 public int getAge()//获取年纪的方法
 {
  return age;
 }
}
class  MapTest
{
 public static void main(String[] args)
 {

  HashMap<Student,String>hm=new HashMap<Student,String>();//加入泛型,明确存入的是学生对象
  hm.put(new Student("zhangsan",25),"beijing");
  hm.put(new Student("lisi",22),"nanjing");
  hm.put(new Student("zhaoliu",24),"tianjin");//添加自定义元素
  hm.put(new Student("zhangsan",25),"tianjin");
  
  Set<Student> keyset=hm.keySet();//用keyset方法将键存入set集合
  
  Iterator<Student> it=keyset.iterator();

   while (it.hasNext())//利用迭代器取出键值
   {
    Student s=it.next();
    String id=hm.get(s);//用map的get方法取出键对应的值
    System.out.println(s.getName()+","+s.getAge()+":::"+id);
   }
 }
}
*/

//练习gsauythhjdiiidkoisoo获取字母出现的次数
//希望打印的结果是h(2)i(4).....

/*
分析:
1.将字符数串转换成字符数组,因为要操作每个字符
2.定义一个treemap集合,因为打印结果,不仅有顺序,而且是成对出现
3.遍历字符数组,将每个字母作为键去map集合中去查,如果返回的是null;说明该字符不在map集合中存在
 如果不是null,说明存在,就将字符存入,把次数增加
4.将结果用字符串返回
*/
class  MapTest
{
 public static void main(String[] args)
 {
  String str="gsauythhjdiiidkoisoo";
  String s=getcharCount(str);//调用方法
  System.out.println(s);
 
 }
 public static String getcharCount(String str)
 {
  TreeMap<Character,Integer>ts=new TreeMap<Character,Integer>();//定义treemap集合并甲泛型
  StringBuilder sb=new StringBuilder();

  char[]chs=str.toCharArray();//将字符数串转换成字符数组,
  for (int x=0; x<chs.length;x++ )
  {
   Integer value=ts.get(chs[x]);//用map集合的get方法,返回值
   if(value==null)
    ts.put(chs[x],1);
   else
   {
    value=value+1;
    ts.put(chs[x],value);//如果不是null,说明存在,就将字符存入,把次数增加
   }
   
  }
  Set<Character> keyset=ts.keySet();//用keyset方法将键存入set集合
  
  Iterator<Character> it=keyset.iterator();

   while (it.hasNext())//利用迭代器取出键值
   {
    Character key=it.next();
    Integer value1=ts.get(key);
    sb.append(key+"("+value1+")");//打印出需要格式
   }
  return sb.toString();
 
 }
}


第二讲  Map扩展知识
 在很多项目中,应用比较多的是一对多的映射关系,这就可以通过嵌套的形式将多个映射定义到一个大的集合中,
 并将大的集合分级处理,形成一个体系。


练习:
/*
map扩展知识。
map集合被使用是因为具备映射关系。
以下是班级对应学生,而学生中学号对应着姓名的映射关系:
"yureban"   Student("01" "zhangsan");
 
"yureban" Student("02" "lisi");
 
"jiuyeban" "01" "wangwu";
"jiuyeban" "02" "zhaoliu";
就如同一个学校有多个教室。每一个教室都有名称。
*/ 
import java.util.*; 
 
class  MapExpandKnow 

    public static void main(String[] args)  
   { 
       //预热班集合 
        HashMap<String,String> yureban=new HashMap<String,String>(); 
        //就业班集合 
        HashMap<String,String> jiuyeban=new HashMap<String,String>(); 
        //学校集合 
  HashMap<String,HashMap<String,String>> czbk=new HashMap<String,HashMap<String,String>>(); 
        //学校中班级集合和名称的映射 
       czbk.put("yureban",yureban); 
       czbk.put("jiuyueban",jiuyeban); 
         
//预热班级中学号与姓名的映射 
       yureban.put("01","zhangsan"); 
        yureban.put("02","lisi"); 
         
        //就业班级中学号与姓名的映射 
       jiuyeban.put("01","wangwu"); 
        jiuyeban.put("02","zhouqi"); 
            
           //直接显示全部学生信息 
       getAllStudentInfo(czbk); 
 
   } 
    //定义一个方法获取全部学生信息,包括在哪个班级,叫什么名字,学号多少 
    public static void getAllStudentInfo(HashMap<String ,HashMap<String,String>> hm) 
    { 
        for (Iterator<String> it=hm.keySet().iterator();it.hasNext() ; )//用keySet取出方式 
       { 
            String s= it.next();//班级名称 
           System.out.println(s+":"); 
           HashMap<String,String> stu=hm.get(s);//班级集合 
 
           getStudentInfo(stu); 
        } 
   } 
     
    //获取班级中学生的信息,包括姓名和学号 
   public static void getStudentInfo(HashMap<String,String> hm) 
   { 
       for (Iterator<String> it=hm.keySet().iterator();it.hasNext() ; ) 
       { 
           String key=it.next();//学号 
           String value=hm.get(key);//姓名 
           System.out.println(key+"..."+value); 
        } 
    } 


第三讲 集合框架和数组工具类
 
1、 Collections:它的出现给集合操作提供了更多的功能。这个类不需要创建对象,内部提供的都是静态方法。
 静态方法:
 Collections.sort(list);//list集合进行元素的自然顺序排序。

2、Collections.max(list);//返回list中字典顺序最大的元素。

3、Collections.reverseOrder();//逆向反转排序。

4、Collections.shuffle(list);//随机对list中的元素进行位置的置换。

5、Collections和Collection有什么区别?
重点:
Collections是个java.util下的类,是针对集合类的一个工具类,提供一系列静态方法,
 实现对集合的查找、排序、替换、线程安全化(将非同步的集合转换成同步的)等操作。
 Collection是个java.util下的接口,它是各种集合结构的父接口,继承于它的接口主要有Set和List,提供了关于集合的一些操作,
 如插入、删除、判断一个元素是否其成员、遍历等。

6、Arrays:
 用于操作数组对象的工具类,里面都是静态方法。
 
 将数组转换成集合,有什么好处呢?用aslist方法,将数组变成集合;
 可以通过list集合中的方法来操作数组中的元素:isEmpty()、contains、indexOf、set;
 注意(局限性):数组是固定长度,不可以使用集合对象增加或者删除等,会改变数组长度的功能方法。比如add、remove、clear。
 (会报不支持操作异常UnsupportedOperationException);
 如果数组中存储的引用数据类型,直接作为集合的元素可以直接用集合方法操作。
 如果数组中存储的是基本数据类型,asList会将数组实体作为集合元素存在。

7、 集合变数组:用的是Collection接口中的方法:toArray();
 如果给toArray传递的指定类型的数据长度小于了集合的size,那么toArray方法,会自定再创建一个该类型的数据,长度为集合的size。
 如果传递的指定的类型的数组的长度大于了集合的size,那么toArray方法,就不会创建新数组,直接使用该数组即可,
 并将集合中的元素存储到数组中,其他为存储元素的位置默认值null。
 所以,在传递指定类型数组时,最好的方式就是指定的长度和size相等的数组。

8、增强for循环:

 for语句,简化了迭代器。
 格式:增强for循环括号里写两个参数,第一个是声明一个变量,第二个就是需要迭代的容器

9、可变参数(...):
 用到函数的参数上,当要操作的同一个类型元素个数不确定的时候,可是用这个方式,这个参数可以接受任意个数的同一类型的数据。
 和以前接收数组不一样的是:
 以前定义数组类型,需要先创建一个数组对象,再将这个数组对象作为参数传递给函数。现在,直接将数组中的元素作为参数传递即可。
 底层其实是将这些元素进行数组的封装,而这个封装动作,是在底层完成的,被隐藏了。所以简化了用户的书写,少了调用者定义数组的动作。
 如果在参数列表中使用了可变参数,可变参数必须定义在参数列表结尾(也就是必须是最后一个参数,否则编译会失败。)。

10、泛型:jdk1.5版本以后出现的一个安全机制。表现格式:<>
 好处:
 1:将运行时期的问题ClassCastException问题转换成了编译失败,体现在编译时期,程序员就可以解决问题。
 2:避免了强制转换的麻烦。
 只要带有<>的类或者接口,都属于带有类型参数的类或者接口,在使用这些类或者接口时,必须给<>中传递一个具体的引用数据类型。
 泛型技术:其实应用在编译时期,是给编译器使用的技术,到了运行时期,泛型就不存在了。为什么?
 因为泛型的擦除:也就是说,编辑器检查了泛型的类型正确后,在生成的类文件中是没有泛型的。
 

import java.util.*;
class  CollectionsDemo
{
 public static void main(String[] args)
 {
  sortDemo();

 }
 
 //定义一个没有比较器的折半查找方法
 public static int halfSearch(List<String> list,String key)
 {
  //定义变量
  int max,min,mid;
  max = list.size()-1;
  min = 0;
  
  while(min<=max)
  {
   
   mid = (max+min)>>1;
   //得到中间的值
   String str = list.get(mid);
   //调用compareTo方法与关键值比较
   int num = str.compareTo(key);
   
   if(num>0)
    max = mid -1;
   else if(num<0)
    min = mid + 1;
   else
    return mid;
  }
  return -min-1;
 }
 //定义带有比较器的折半方法
 public static int halfSearch(List<String> list,String key,Comparator<String> cmp)
 {
  int max,min,mid;
  max = list.size()-1;
  min = 0;

  while(min<=max)
  {
   mid = (max+min)>>1;//  /2;

   String str = list.get(mid);
   //调用compare方法与关键值比较
   int num = cmp.compare(str,key);
   if(num>0)
    max = mid -1;
   else if(num<0)
    min = mid + 1;
   else
    return mid;
  }
  return -min-1;
 }


 public static void maxDemo()
 {
  List<String> list = new ArrayList<String>();

  list.add("abcd");
  list.add("aaa");
  //用集合工具的sort方法进行排序
  Collections.sort(list);
  sop(list);
  //用集合工具的max方法求出最大值
  String max = Collections.max(list/*,new StrLenComparator()*/);
  sop("max="+max);
 }

 public static void sortDemo()
 {
  List<String> list = new ArrayList<String>();

  list.add("abcd");
  list.add("aaa");
  list.add("zz");
  //用集合工具的sort方法进行排序
  sop(list);

  //Collections.sort(list);
  Collections.sort(list,new StrLenComparator());
  //Collections.swap(list,1,2);
  sop(list);
  
 }

 public static void sop(Object obj)
 {
  System.out.println(obj);
 }
}


class StrLenComparator implements Comparator<String>
{
 public int compare(String s1,String s2)
 {
  if(s1.length()>s2.length())
   return 1;
  if(s1.length()<s2.length())
   return -1;
  return s1.compareTo(s2);
 }
}

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

1 0