美文网首页JavaJava学习笔记
Java学习笔记 (三)

Java学习笔记 (三)

作者: 翌日千里 | 来源:发表于2016-06-09 10:10 被阅读45次

    Object类:完整的类最好覆写Object类的hashCode()equals()toString()3个方法。
    在类集中提供了4种常见的输出方式:

    1. Iterator:迭代输出,使用最多的输出方式。
    2. ListIterator:Iterator的子接口,专门用于输出List中的内容。
    3. Enumeration:是旧接口,功能与Iterator类似。
    4. foreach:jdk1.5之后新增,输出数组和集合。
    Iterator——迭代器:
    1. 二要素:
      i. 迭代器必定从属于某个容器,其作用就是用来遍历所属容器中的元素的。
      ii.迭代器是在容器的数据视图之上进行迭代,因此不能再迭代过程中修改容器中的数据,否则会抛出异常!除非使用迭代器的专用方法对数据进行修改。
    2. Java的迭代器只在Collection中有,而Map没有迭代器,它有不同的迭代方法。
    3. 迭代器的终极目标:就是用统一的方法来迭代不同类型的集合!可能由于不同集合的内部数据结构不尽相同,如果要自己纯手工迭代的话相互之间会有很大的差别,而迭代器的作用就是统一的方法对不同的集合进行迭代,而在迭代器底层隐藏不同集合之间的差异,从而为迭代提供最大的方便。
    4. 用迭代器迭代的步骤:
      i. 第一步肯定是先获取集合的迭代器:调用集合的iterator方法就能获得,Iterator<E> Collection.iterator(); // 是Collection的对象方法
      ii. 使用迭代器的hasNext、next往下迭代。
    Iterator的常用方法:
    * boolean hasNext(); // 是否还有下一个元素(肯定有一个位置指针维护者当前迭代的位置)
    * Object next();        // 取出下一个元素并返回
    * void remove();       // 从容器中删除当前元素(即上一个next代表的那个元素),直接会改变容器中的数据!  
    

     由于Java容器都是泛型类模板,因此容器可以记忆元素的具体类型,因此可以放心使用,只不过取出元素后要进行类型转换后才能正常使用,
    使用迭代器next获得的元素是一个集合中对应元素的深拷贝(即数据视图),如果对迭代变量进行修改是不会修改集合中的原数据的。同样,也不能直接在迭代过程中使用c.remove等方法对集合进行修改,因为迭代器已经锁定住集合了,强行修改会抛出异常!只能用Iterator的专用修改集合元素的方法修改才是正确的,就像上面的Iterator.remove方法。
    模板:

    public class Test {  
          
        public static void main(String[] args) {  
            Collection c = new ArrayList(); // ArrayList是Collection的一个实现类,默认元素类型为Object  
              
            Iterator it = c.iterator();  
            while (it.hasNext()) {  
                Type var = it.next(); // 迭代值(数据视图)  
                对var进行操作;  
                c.remove(); // 错误!!在迭代过程中使用非迭代器方法对集合进行修改会直接抛出异常!!  
            }  
        }  
    }  
    

    实际上,Iterator迭代的“集合”是真正集合的视图,视图和真实数据之间是一一映射的关系,如果此时使用非迭代器方法对真实数据进行修改就会导致真实数据和映像之间不一致,因此会抛出异常,而迭代器的修改方法可以保证这种映射的一致性,即迭代器先对视图进行修改,然后将视图的修改更新到真实数据,但是反向就是无效的,因为映像自己是知道关联的是哪个真实数据,但是真实数据本身不知道有哪些映像和我关联的,即真实数据永远是被动的,而映像是主动的。

    ListIterator

    ListIterator是Iterator的子接口,专门用于输出List中的内容。只能从List接口实例化。可以进行双向迭代。

    public class ListIteratorDemo01{
        public static void main(String argsp[]){
            List<String> all = new ArrayList<String>() ;
            all.add("hello") ;
            all.add("_") ;
            all.add("world") ;
            ListIterator<String> iter = all.listIterator() ;
            System.out.print("由前向后输出:") ;
            while(iter.hasNext()){
                String str = iter.next() ;
                System.out.print(str + "、") ;
            }
            System.out.print("\n由后向前输出:") ;
            while(iter.hasPrevious()){
                String str = iter.previous() ;
                System.out.print(str + "、") ;
            }
        }
    };
    

    输出结果:
    由前向后输出:hello、、world、
    由后向前输出:world、
    、hello、

    • 在使用ListIterator接口进行双向输出时,如果想完成由后向前输出则一定要先进行由前往后输出。
    • foreach也可以输出集合。for(类 : 对象 集合)
    • Enumeration 废弃的接口,旧类,已被扩充。
    Map接口
    Map 图谱

    Map 就是关联数组,也常被称为“映射表”或是“字典”,是键值对的集合容器,键不能重复出现是他的基本限制

    如上图所示,Map 都继承自 Map 接口,标准 Java 类库中包含了几种 Map 的基本实现:

    1. TreeMap -- 基于红黑树的 Map 实现,因此是有序的,作为键加入 TreeMap 的对象必须实现 Comparable 接口,以便他可以被比较
    2. HashMp -- 基于哈希表的 Map 实现,虽然无序,但是优势却在于其查询速度
    3. LinkedHaskMap -- 在 HashMap 的基础上实现的双链表复合结构,在查询速度的基础上保证了插入顺序
    4. WeakHashMap -- WeakHashMap 与 HashMap 的用法基本相同,Hash 的 key 保留对象的强引用,即只要 HashMap 5. 对象不被销毁,其对象所有 key 所引用的对象不会被垃圾回收,HashMap 也不会自动删除这些key所对应的键值对对象。但 WeakHashMap 的 key 所引用的对象没有被其他强引用变量所引用,则这些 key 所引用的对象可能被回收。WeakHashMap 中的每个 key 对象保存了实际对象的弱引用,当回收了该 key 所对应的实际对象后,WeakHashMap 会自动删除该key所对应的键值对
    5. ConcurrentHashMap -- ConcurrentHashMap 保证了线程安全,一般用在多线程环境中
    6. IdentityHashMap -- 与 HashMap 一样,IdentityHashMap 也不保证存储的顺序,他与 HashMap 的区别在于,它用来比较键是否相同的方法是 == 而不是 equals 方法,因此值相同但地址不同的两个对象是允许出现的,一般只在解决特殊问题时才会使用

    Map 接口定义了基本的 map 操作方法:

    方法名 方法 说明
    get V get(Object key) 获取 key 对应的值
    put V put(K key, V value) 向容器中添加键值对
    putAll void putAll(Map m) 将 Map m 中的所有元素添加到容器中
    remove V remove(Object key) 删除指定的 key
    clear void clear() 清除容器中所有元素
    containsKey boolean containsKey(Object key) 判断 key 是否存在
    containsValue boolean containsValue(Object value) 判断 value 是否存在
    isEmpty boolean isEmpty() 判断容器是否为空
    keySet Set keySet() 返回由所有 key 组成的 set
    values Collection values() 返回由所有 value 组成的 Collection
    entrySet Set> entrySet(); 获取 Map 内部接口 Entry 组成的 Set

    TreeMap : String类型实现了comparable接口,如果使用自定义类的话需要先实现Comparable接口。
    对象的四种引用方式:

    • 强引用
      强引用是最常见的的一种引用,类似"Object obj = new Object()"之类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用对象。
    • 软引用 软引用是用来描述一些还有用但并非必需的对象。对于软引用的对象,在系统将要发生内存溢出之前,会把这些对象列入回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出溢出异常。JDK1.2之后使用SoftReference来实现软引用。
    • 弱引用
      弱引用用来描述非必需的对象,但是强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集器工作时,无论当前内存是否足够,都会回收弱引用所关联的对象。JDK1.2之后使用WeakReference来实现弱引用。
    • 虚引用
      虚引用又称幽灵引用或者幻影引用,他是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间存在影响,也无法通过虚引用来获取一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。JDK1.2之后使用PhantomReference来实现虚引用。

    总结:强引用的对象一定不会被当成垃圾回收的,软引用的对象会在内存不足时被当成垃圾回收掉,弱引用的对象在下一次垃圾回收时就直接回收掉。

    Map接口的注意事项:

    1. 不能直接使用迭代(Iterator,foreach)输出Map中的全部内容。如果要用需按照以下4步。
      a. 将map的实例通过entrySet()方法变为Set接口对象。
      b. 通过Set接口实例为Iterator实例化。
      c. 通过Iterator迭代输出,每个内容都是Map.Entry的对象。
      d. 通过Map.Entry进行key→value的分离。
    • 使用Iterator输出Map实例
    public class IteratorDemo04 {
        public static void main(String[] args) {
            Map<String, String> map = null;     // 声明Map对象,其中key和value的类型为String
            map = new HashMap<String,String>();
            map.put("lc", "lichuang");      // 增加内容
            map.put("jsf", "jisaifu");      // 增加内容
            map.put("wzc", "wangzhicheng");     // 增加内容
            Set<Map.Entry<String, String>> allSet = null;
            allSet = map.entrySet();
            Iterator<Map.Entry<String, String>> iter = null;
            iter = allSet.iterator();
            while (iter.hasNext()) {
                Map.Entry<String, String> me = iter.next();
                System.out.println(me.getKey() + "-->" + me.getValue());
            }
        }
    }
    执行结果:  
    wzc-->wangzhicheng
    lc-->lichuang
    jsf-->jisaifu
    
    • 使用foreach输出Map实例:
    public class ForeachDemo02{
        public static void main(String args[]){
            Map<String,String> map = null; // 声明Map对象,其中key和value的类型为String
            map = new HashMap<String,String>() ;
            map.put("lc", "lichuang");      // 增加内容
            map.put("jsf", "jisaifu");      // 增加内容
            map.put("wzc", "wangzhicheng");     // 增加内容
            for(Map.Entry<String,String> me:map.entrySet()){
                System.out.println(me.getKey() + " --> " + me.getValue()) ;
            }
        }
    }
    

    如果要使用一个自定义的对象表示Map中的key,则对象所在类中一定要覆写equals()和hashCode()方法,否则无法找到对应的value。

    class Person{
        private String name ;
        private int age ;
        public Person(String name,int age){
            this.name = name ;
            this.age = age ;
        }
        public String toString(){
            return "姓名:" + this.name + ";年龄:" + this.age ;
        }
        public boolean equals(Object obj){
            if(this==obj){
                return true ;
            }
            if(!(obj instanceof Person)){
                return false ;
            }
            Person p = (Person)obj ;
            if(this.name.equals(p.name)&&this.age==p.age){
                return true ;
            }else{
                return false ;
            }
        }
        public int hashCode(){
            return this.name.hashCode() * this.age ;
        }
    };
    public class HashMapDemo08{
        public static void main(String args[]){
            Map<Person,String> map = null ;
            map = new HashMap<Person,String>() ;
            map.put(new Person("张三",30),"zhangsan");    // 增加内容
            System.out.println(map.get(new Person("张三",30))) ;
        }
    }
    

    相关文章

      网友评论

        本文标题:Java学习笔记 (三)

        本文链接:https://www.haomeiwen.com/subject/ouhjdttx.html