zoukankan      html  css  js  c++  java
  • java集合(二)

    HashMap,HashTable,TreeMap区别和用法

     java为数据结构中的映射定义了一个接口java.util.Map,而HashMap Hashtable和TreeMap就是它的实现类。Map是将键映射到值的对象,一个映射不能包含重复的键;每个键最多只能映射一个一个值。

        Hashtable 与 HashMap类似,但是主要有6点不同。

       1. 继承的父类不同。Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。但二者都实现了Map接口。

             2.线程安全性不同。HashTable的方法是同步的,HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。

          如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力.,这个区别就像Vector和ArrayList一样。   

             3.key和value是否允许null值

        HashTable的key和value都不允许null值,。  HashMap的 key 和 value 允许null值, 但是key值只能有一个null值,允许多条记录的值为Null。因为hashmap如果key值相同,新的key, value将替代旧的。 

             4. 是否提供contains方法

          HashMap包含了containsvalue和containsKey 方法,不包含有contains,而 HashTable只有一个 contains(Object value) 功能 和 HashMap中的 containsValue(Object value)功能一样。

             5. 内部实现使用的数组初始化和扩容方式不同。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。   

             6. hash值不同  . 哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

     

    hashmap和treemap什么区别?底层数据结构是什么?


    无序: 不保证元素迭代顺序是按照插入时的顺序。

      1. 底层实现不同。HashMap:数组方式存储key/value 。TreeMap:基于红黑二叉树的NavigableMap的实现,两个线程都不安全

      2. HashMap 键允许为空,TreeMap键不能为空。

      3.判断重复元素(指的键)不同,HashMap的键重复标准为重写equals() 和HashCode() , TreeMap 的键重复标准是比较器返回为0.  

        存入TreeMap的元素应当实现Comparable接口或者实现Comparator接口,两个相比较的key不得抛出classCastException。主要用于存入元素的时候对元素进行自动排序,迭代输出的时候就按排序顺序输出

         4.TreeMap无序的,保存的记录根据键排序,默认是升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。而HashMap 是无须的 ,自然排序。

      5.TreeMap添加的类型取决于第一个添加的键的类型(加上泛型就没有区别了)

     

    TreeMap tmp=new TreeMap();
    
    Iterator iterator_2 = tmp.keySet().iterator();
    
    while (iterator_2.hasNext()) {   
    
            Object key = iterator_2.next();   
    
            System.out.println(“tmp.get(key) is :”+tmp.get(key));  
    }

    hashMap 底层原理:参考:      https://blog.csdn.net/u010010428/article/details/51258238

      HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,

      当 put() 需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置再根据equals方法决定其在该数组位置上的链表中的存储位置

      当 get() 需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。

      

      HashMap数组扩容时,原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize,这是一个非常消耗性能的操作,故预设元素的个数能够有效的提高HashMap的性能。

    Map集合中HashMap

    package HashMap类的常用方法;
    
    import java.util.Collection;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    
    public class Test {
        public static void main(String[] args) {
    //1.继承关系        Map接口定义了键映射到值的规则,而AbstractMap类提供 Map 接口的骨干实现。
    /*        public class HashMap<K,V>
            extends AbstractMap<K,V>
            implements Map<K,V>, Cloneable, Serializable        
    */
    //2.构造函数  涉及到底层原理,暂时不做解释
    /*        HashMap():构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
            HashMap(int initialCapacity):构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。
            HashMap(int initialCapacity, float loadFactor):构造一个带指定初始容量和加载因子的空 HashMap。
    */
    //3.实现了Map接口的常用方法
    /*      1. Set entrySet()  (返回当前Map中所有的entry对象(Entry对象就包装了key,values),使用Set存储起来。)
           2. Set keySet()    返回Map当中所有的key,存储到一个Set集合当中。
          3. Collection values()    返回所有的values,存储到一个Collection。什么返回Collection?
                                    因为values 有重复,如果返回Set,就不能含有重复的元素.
    
          4. Object get(Object key)  通过key查找对应的值。
     */
    //举例:
            Map map = new HashMap();
            map.put(1, "我好");
            map.put(2, "你好");
            map.put(3, "大家好");
            map.put(4, "啦啦啦");
            map.put(5, "么么哒");
    /*        
            Set set  = map.entrySet();
            System.out.println(set);    // [1=我好, 2=你好, 3=大家好, 4=啦啦啦, 5=么么哒]
            
            Set keys = map.keySet();
            System.out.println(keys);  // [1, 2, 3, 4, 5]
            
            Collection col = map.values();
            System.out.println(col);   // [我好, 你好, 大家好, 啦啦啦, 么么哒]
            
            Object obj= map.get(5);
            System.out.println(obj);   //么么哒
    */        
    //5.Map的遍历方式
    /*        前言:  1. 不能使用普通for循环遍历Map元素,因为没有索引。
                   2. 使用增强for行不行? 不能,没有实现Iterable接口,foreach就是通过Iterable接口在序列中进行移动。
                   3. Map里面并没有获得迭代器的方法;所有不能使用迭代器
          方式一:
              先通过keySet()方法取到所有key
            然后遍历keySet,依次通过Object get(Object key)方法,来查找value。
    */
            Set keys = map.keySet();
            for (Object object : keys) {
                System.out.print(object+":"+map.get(object));// "1:我好2:你好3:大家好4:啦啦啦5:么么哒"
            }
    /*  方式二:
             先得到所有的Entry对象,遍历Entry对象的集合,然后依次从Entry对象中调用方法:getKey(),getValue() 
     */
            Set set  = map.entrySet();
            for (Object object : set) {
                Entry obj = (Entry)object;  //需要把Object强制转成 Entry类型
                System.out.print(obj.getKey()+":"+obj.getValue());// "1:我好2:你好3:大家好4:啦啦啦5:么么哒"
            }
    //6.使用Map集合解决:打印 字符串中 出现最多字符的  次数
    /*    实例:Map使用示例: 有如下字符串,String str = “aaaabbbyyyccc”;
             *    1.统计出str中每一个字符的个数   比如 a - 4    b - 3
             *    2.找出并打印,次数最多的字符和次数
    */
    /*
         public class Test {
        public static void main(String[] args) {
            String str = "aaaabbbyyyccc";
            Map map = getChar(str);
            System.out.println(map);
            System.out.println(getCharAndValue(map));
        }
    //统计每个字符出现的次数,并存储到map集合中
        public static Map getChar(String str){
            Map map = null;
            if(str!=null&&str.length()>0){
                map = new HashMap();
                for(char ch:str.toCharArray()){
                    if(map.containsKey(ch)){
                        map.put(ch, (int)map.get(ch)+1);
                    }else{
                        map.put(ch, 1);
                    }
                }
            }
            return map;
        }
    // 打印次数最多的字符和次数 。    
        public static String getCharAndValue(Map map){
            if(map!=null&&map.size()!=0){
                Collection values = map.values();
                
            //方法一: 直接调用Collections里面的max方法    
                int max = (int)Collections.max(values);
                
            //方法二:用Collection中的toArray方法,把Collection转换成数组,然后调用Arrays中的工具方法sort求出
            //    Object[] arr = values.toArray();
            //    Arrays.sort(arr);
            //    int max = (int)arr[arr.length-1];
                
                String str = "";
                Set set = map.keySet();
                for(Object obj : set){
                    if(map.get(obj).equals(max)){
                        str = obj + ":"+max;
                    }
                }
                return str;
            }
            return null;
        }
    }
    */              
        }
    }

    顺便简单介绍下——泛型

    1. 泛型类

    public class Point<T> {
    	private T x;
    	private T y;
    	public Point(T x, T y) {
    		super();
    		this.x = x;
    		this.y = y;
    	}
    	public T getX() {
    		return x;
    	}
    	public void setX(T x) {
    		this.x = x;
    	}
    	public T getY() {
    		return y;
    	}
    	public void setY(T y) {
    		this.y = y;
    	}
    }
    

    2.泛型方法:只有在public 与 返回值中间声明了<T>的方法才是泛型方法

    public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
      IllegalAccessException{
            T instance = tClass.newInstance();
            return instance;
    }
    

     

    Object obj = genericMethod(Class.forName("com.test.test"));
    

      

    3. 泛型的上限、下限

    ?号  :表示通配符,不确定的类型,可以表示任意类型【? extends Object】 ;

    ?  extends Number :表示通配符?的上限 ,必须是NumberNumber的子类

    ?  Super   Number: 表示通配符?的下限,必须是NumberNumber的父类

    public class GenericTest {
    	public static void main(String[] args) {
    		GenericTest test = new GenericTest();
    		test.test(new ArrayList<Integer>());
    		test.test2(new ArrayList<Object>());
    	}
    	
    	public void test(List<? extends Number> list){     }
    	public void test2(List<? super Number> list) {     }
    }
    

     4、 泛型的优点

    编译时类型检查,消除强制类型转换,没有泛型的返回,我们可以认为是一个Object,在使用时需要对其进行强制转换,在转换过程中,非常容易出现ClassCastException。

      

  • 相关阅读:
    494 Target Sum 目标和
    493 Reverse Pairs 翻转对
    492 Construct the Rectangle 构建矩形
    491 Increasing Subsequences 递增子序列
    488 Zuma Game 祖玛游戏
    486 Predict the Winner 预测赢家
    485 Max Consecutive Ones 最大连续1的个数
    483 Smallest Good Base
    Django Form组件
    Django Auth组件
  • 原文地址:https://www.cnblogs.com/gshao/p/10134268.html
Copyright © 2011-2022 走看看