集合

来源:互联网 发布:mkv格式播放器 mac 编辑:程序博客网 时间:2024/05/18 02:33


 Set集合的实现类HashSet

Set是无序,用于存储不重复的对象集合。在Set集合中存储的对象中,不存在两个对象equals比较为true的情况。

1)HashSet和TreeSet是Set集合的两个常见的实现类,分别用hash表和排序二叉树的方式实现了Set集合。HashSet是使用散列算法实现Set的。

2)Set集合没有get(intindex)方法,我们不能像使用List那样,根据下标获取元素。想获取元素需要使用Iterator。

3)向集合添加元素也使用add方法,但是add方法不是向集合末尾追加元素,因为无序。

4)宏观上讲:元素的顺序和存放顺序是不同的,但是在内容不变的前提下,存放顺序是相同的,但在我们使用的时候,要当作是无序的使用。

       Set<String> set=newHashSet<String>();//多态

       //也可HashSet<String> set=new HashSet<String>();

       set.add("One");      set.add("Two");    set.add("Three");   Iterator<String> it=set.iterator();

       while(it.hasNext()){      String element=it.next();              System.out.print(element+"");     }

       for(String element:set){        System.out.print(element+" ");     }//新循环遍历Set集合

5)hashCode对HashSet的影响:若我们不重写hashCode,那么使用的就是Object提供的,而该方法是返回地址(句柄)!换句话说,就是不同的对象,hashCode不同。

6)对于重写了equals方法的对象,强烈要求重写继承自Object类的hashCode方法的,因为重写hashCode方法与否会对集合操作有影响!

7)重写hashCode方法需要注意两点:

①与equals方法的一致性,即equals比较返回为true的对象其hashCode方法返回值应该相同。

②hashCode返回的数值应该符合hash算法要求,如果有很多对象的hashCode方法返回值都相同,则会大大降低hash表的效率。一般情况下,可以使用IDE(如Eclipse)提供的工具自动生成hashCode方法。

8)booleancontains(Object o)方法:查看对象是否在set中被包含。下例虽然有新创建的对象,但是通过散列算法找到了位置后,和里面存放的元素进行equals比较为true,所以依然认为是被包含的(重写equals了时)。

              Set<Point> set=newHashSet<Point>();              set.add(newPoint(1,2));

              set.add(new Point(3,4));   System.out.println(set.contains(new Point(1,2)));         

9)HashCode方法和equals方法都重写时对hashSet的影响:将两个对象同时放入HashSet集合,发现存在,不再放入(不重复集)。当我们重写了Point的equals方法和hashCode方法后,我们发现虽然p1和p2是两个对象,但是当我们将他们同时放入集合时,p2对象并没有被添加进集合。因为p1在放入后,p2放入时根据p2的hashCode计算的位置相同,且p2与该位置的p1的equals比较为true, hashSet认为该对象已经存在,所以拒绝将p2存入集合。

              Set<Point> set=newHashSet<Point>();

              Point p1=new Point(1,2);             Point p2=new Point(1,2);

              System.out.println("两者是否同一对象:"+(p1==p2));

              System.out.println("两者内容是否一样:"+p1.equals(p2));

              System.out.println("两者HashCode是否一样:"+  (p1.hashCode()==p2.hashCode()));

              set.add(p1);    set.add(p2);    System.out.println("hashset集合的元素数"+set.size());

              for(Point p:set){            System.out.println(p);           }

10)不重写hashCode方法,但是重写了equals方法对hashSet的影响:两个对象都可以放入HashStet集合中,因为两个对象具有不用的hashCode值,那么当他们在放入集合时,通过hashCode值进行的散列算法结果就不同。那么他们会被放入集合的不同位置,位置不相同,HashSet则认为它们不同,所以他们可以全部被放入集合。

11)重写了hashCode方法,但是不重写equals方法对hashSet的影响:在hashCode相同的情况下,在存放元素时,他们会在相同的位置,hashSet会在相同位置上将后放入的对象与该位置其他对象一次进行equals比较,若不相同,则将其存入在同一个位置存入若干元素,这些元素会被放入一个链表中。由此可以看出,我们应该尽量使得多种类的不同对象的hashcode值不同,这样才可以提高HashSet在检索元素时的效率,否则可能检索效率还不如List。

12)结论:不同对象存放时,不会保存hashCode相同并且equals相同的对象,缺一不可。否则HashSet不认为他们是重复对象。

Map集合的实现类HashMap

       Map接口定义的集合又称为查找表,用于存储所谓“Key-Value”键值对。Key可以看成是Value的索引。而往往Key是Value的一部分内容。

       1)Key不可以重复,但所保存的Value可以重复。

       2)根据内部结构的不同,Map接口有多种实现类,其中常用的有内部为hash表实现的HashMap和内部为排序二叉树实现的TreeMap。同样这样的数据结构在存放数据时,也不建议存放两种以上的数据类型,所以,通常我们在使用Map时也要使用泛型约束存储内容的类型。

       3)创建Map时使用泛型,这里要约束两个类型,一个是key的类型,一个是value的类型。

       4)基本原理图:


       5)HashMap集合中常用的方法:

              ①Vput(K Key,V value):将元素以Key-Value的形式放入map。若重复保存相同的key时,实际的操作是替换Key所对应的value值。

              ②Vget(Object key):返回key所对应的value值。如果不存在则返回null。

              ③booleancontainsKey(Object Key):判断集合中是否包含指定的Key。

              ④booleancontainsValue(Object value):判断集合中是否包含指定的Value。

       6)若给定的key在map中不存在则返回null,所以,原则上在从map中获取元素时要先判断是否有该元素,之后再使用,避免空指针异常的出现。Map在获取元素时非常有针对性,集合想获取元素需要遍历集合内容,而Map不需要,你只要给他特定的key就可以获取该元素。

              Map<String,Point> map=newHashMap<String,Point>();

              map.put("1,2", newPoint(1,2));   map.put("3,4",new Point(3,4));

              Point p=map.get("1,2");  System.out.println("x="+p.getX()+",y="+p.getY());

              map.put("1,2", newPoint(5,6));//会替换之前的

              p=map.get("1,2");   System.out.println("x="+p.getX()+",y="+p.getY());

              p=map.get("haha");       System.out.println("x="+p.getX()+",y="+p.getY());//会报空指异常

              eg:统计每个数字出现的次数。步骤:①将字符串str根据“,”拆分。②创建map。③循环拆分后的字符串数组。④蒋梅一个数字作为key在map中检查是否包含。⑤包含则对value值累加1。⑥不包含则使用该数字作为key,value为1存入map。

              Stringstr="123,456,789,456,789,225,698,759,456";

              String[]array=str.split(",");

              Map<String,Integer> map=newHashMap<String,Integer>();

              for(String number:array){     if(map.containsKey(number)){

                     int sum=map.get(number);//将原来统计的数字取出  sum++;   //对统计数字加1

                     map.put(number, sum);  //放回 map.put(number, map.get(number)+1);等同上三部

                     }else{  map.put(number, 1);//第一次出现value为1        }            }

              System.out.println(map);//HashMap也重写了toString()

       7)计算机中有这么一句话:越灵活的程序性能越差,顾及的多了。

       8)遍历HashMap方式一:获取所有的key并根据key获取value从而达到遍历的效果(即迭代Key)。keySet()方法:是HashMap获取所有key的方法,该方法可以获取保存在map下所有的key并以Set集合的形式返回。

              Map<String,Point> map=newHashMap<String,Point>();

              map.put("1,2", newPoint(1,2));          map.put("2,3",new Point(2,3));

              map.put("3,4", newPoint(3,4));          map.put("4,5", new Point(4,5));

              /** 因为key在HashMap的泛型中规定了类型为String,所以返回的Set中的元素也是String,为了更好的使用,我们在定义Set类型变量时也应该加上泛型*/

              Set<String>keyset=map.keySet();

              for(String key:keyset){  Point p=map.get(key);//根据key获取value

                     System.out.println(key+":"+p.getX()+","+p.getY());         }

              for(Iterator<String>it=keyset.iterator()       ;  it.hasNext() ;  ){//普通for循环

                     String key=it.next();      Point p=map.get(key);

                     System.out.println(key+":"+p.getX()+","+p.getY());         }

       9)LinkedHashMap:用法和HashMap相同,内部维护着一个链表,可以使其存放元素时的顺序与迭代时一致。

       10)Entry类,遍历HashMap方式二:以“键值对”的形式迭代。Map支持另一个方法entrySet():该方法返回一个Set集合,里面的元素是map中的每一组键值对,Map以Entry类的实例来描述每一个键值对。其有两个方法:getKey()获取key值;getValue()获取value值。Entry也需要泛型的约束,其约束的泛型应该和Map相同!Entry所在位置:java.util.Map.Entry。

              Map<String,Point> map=newLinkedHashMap<String,Point>();

              map.put("1,2", newPoint(1,2));          map.put("2,3",new Point(2,3));

              map.put("3,4", newPoint(3,4));          map.put("4,5",new Point(4,5));   //泛型套泛型

              Set<Entry<String,Point>>entrySet=map.entrySet();//Set的泛型不会变,就是Entry

              for(Entry<String,Point>entry:entrySet){

                     Stringkey=entry.getKey();//获取key   Pointp=entry.getValue();//获取value

                     System.out.println(key+","+p.getX()+","+p.getY());         }

11)List、Map、Set三个接口存储元素时各有什么特点:

①List:是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。

②Set:是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。

③Map:请注意,Map没有继承Collection接口,Map提供key到value的映射。

0 0
原创粉丝点击