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。

      

  • 相关阅读:
    Centos6.10-FastDFS-存储器Http配置
    Centos6.10-FastDFS-Storage.conf配置示例
    Centos6.10-FastDFS-Tracker.conf示例配置
    sublime不支持ascill编码办法
    VMware虚拟磁盘修复
    Centos610安装Nexus
    JavaWeb项目用浏览器打开网页出现Session Error提示的解决办法
    Ext里dialog弹窗关闭与父窗口刷新问题总结
    js里常见的三种请求方式$.ajax、$.post、$.get分析
    formValidation单个输入框值改变时校验
  • 原文地址:https://www.cnblogs.com/gshao/p/10134268.html
Copyright © 2011-2022 走看看