1. 程式人生 > >java基礎--集合框架(強弱)

java基礎--集合框架(強弱)

字符 收集 erro sts 軟引用 每一個 框架 bject 缺陷

(1) 隊列:單向和雙向

一、單向:一端操作
1、一般:FIFO
2、優先和堆棧: LIFO

技術分享圖片

二、雙向:兩端操作,頭或尾操作

技術分享圖片

技術分享圖片
package com.zwj.que;
import java.util.ArrayDeque;
import java.util.Queue;

/**
 * 使用隊列模擬銀行存款業務
 * @author Administrator
 *
 */
public class Demo01 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Queue
<Request> que =new ArrayDeque<Request>(); //模擬排隊情況 for(int i=0;i<10;i++){ final int num =i; que.offer(new Request(){ @Override public void deposit() { System.out.println("第"+num+"個人,辦理存款業務,存款額度為:"+(Math.random()*10000)); } }); } dealWith(que); }
//處理業務 public static void dealWith(Queue<Request> que){ Request req =null; while(null!=(req=que.poll())){ req.deposit(); } } } interface Request{ //存款 void deposit(); } /*第0個人,辦理存款業務,存款額度為:2046.2981088665576 第1個人,辦理存款業務,存款額度為:3183.132919756152 第2個人,辦理存款業務,存款額度為:3111.663940566103 第3個人,辦理存款業務,存款額度為:6373.576490760695 第4個人,辦理存款業務,存款額度為:3984.127328799619 第5個人,辦理存款業務,存款額度為:6668.63282594925 第6個人,辦理存款業務,存款額度為:8753.13596300943 第7個人,辦理存款業務,存款額度為:7154.137882713864 第8個人,辦理存款業務,存款額度為:6832.804030880775 第9個人,辦理存款業務,存款額度為:4460.875767507243
*/
Demo01 使用隊列模擬銀行存款業務 技術分享圖片
package com.zwj.que;
//測試自定義堆棧
public class Demo02 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        MyStack<String> backHistory =new MyStack<String>(3);
        backHistory.push("www.baidu.com");
        backHistory.push("www.google.com");
        backHistory.push("www.sina.com");
        
        System.out.println("大小:"+backHistory.size());
        
        //遍歷
        String item=null;
        while(null!=(item=backHistory.pop())){
            System.out.println(item);
        }
    }

}
Demo02 測試自定義堆棧 技術分享圖片
package com.zwj.que;
import java.util.ArrayDeque;
import java.util.Deque;

/**
 * 使用隊列實現自定義堆棧
 * 1、彈
 * 2、壓
 * 3、獲取頭
 * @author Administrator
 *
 * @param <E>
 */
public class MyStack<E> {
    //容器
    private Deque<E> container =new ArrayDeque<E>();
    //容量
    private int cap;
    public MyStack(int cap) {
        super();
        this.cap = cap;
    }
    
    //壓棧
    public boolean push(E e){
        if(container.size()+1>cap){
            return false;
        }
        return container.offerLast(e);
        
    }
    //彈棧
    public E pop(){
        return container.pollLast();
    }
    //獲取
    public E peek(){
        return container.peekLast();
    }
    
    public int size(){
        return this.container.size();        
    }
}
MyStack 現自定義堆棧

(2) 比較古老的接口
枚舉Enumeration,作用和Iterator類似,都是輸出數據
方法:
hasMoreElements()
nextElement()

技術分享圖片
package com.others.en;

import java.util.Enumeration;
import java.util.Vector;

/**
 * Enumeration 的使用
 * 1、判斷  hasMoreElements()
 * 2、獲取 nextElement()
 * 
 * Vector 的 elements()方法
 * 
 * 
 * @author Administrator
 *
 */
public class Demo01 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Vector<String> vector =new Vector<String>();
        vector.add("javase");
        vector.add("html");
        vector.add("oracle");
        
        //遍歷該Vector
        Enumeration<String> en =vector.elements();
        while(en.hasMoreElements()){
            System.out.println(en.nextElement());
        }
        
        
    }

}
Enumeration 的使用

應用
Vector :elements()
StringTokenizer

技術分享圖片
package com.bjsxt.others.en;

import java.util.StringTokenizer;

/**
 * Enumeration 子類
 * StringTokenizer:String split() 字符串分割
 * 不支持正則表達式
 * 
 * StringTokenizer(String str, String delim) 

 * @author Administrator
 *
 */
public class Demo02 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        String emailStr="[email protected];[email protected];[email protected]";
        StringTokenizer token =new StringTokenizer(emailStr,";");
        //遍歷獲取
        while(token.hasMoreElements()){
            System.out.println(token.nextElement());
        }
    }

}
Demo02 StringTokenizer:String split() 字符串分割 不支持正則表達式

(3)Java四種引用包括強引用,軟引用,弱引用,虛引用。

⑴強引用(StrongReference)
強引用是使用最普遍的引用。如果一個對象具有強引用,那垃圾回收器絕不會回收它。當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足的問題。 ps:強引用其實也就是我們平時A a = new A()這個意思。

⑵軟引用(SoftReference)
如果一個對象只具有軟引用,則內存空間足夠,垃圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存(下文給出示例)。
軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。

⑶弱引用(WeakReference)
弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由於垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。
弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。

⑷虛引用(PhantomReference)
“虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定對象的生命周期。如果一個對象僅持有虛引用,那麽它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之 關聯的引用隊列中。

使用軟引用構建敏感數據的緩存
1 為什麽需要使用軟引用

首先,我們看一個雇員信息查詢系統的實例。我們將使用一個Java語言實現的雇員信息查詢系統查詢存儲在磁盤文件或者數據庫中的雇員人事檔案信息。作為一個用戶,我們完全有可能需要回頭去查看幾分鐘甚至幾秒鐘前查看過的雇員檔案信息(同樣,我們在瀏覽WEB頁面的時候也經常會使用“後退”按鈕)。這時我們通常會有兩種程序實現方式:一種是把過去查看過的雇員信息保存在內存中,每一個存儲了雇員檔案信息的Java對象的生命周期貫穿整個應用程序始終;另一種是當用戶開始查看其他雇員的檔案信息的時候,把存儲了當前所查看的雇員檔案信息的Java對象結束引用,使得垃圾收集線程可以回收其所占用的內存空間,當用戶再次需要瀏覽該雇員的檔案信息的時候,重新構建該雇員的信息。很顯然,第一種實現方法將造成大量的內存浪費,而第二種實現的缺陷在於即使垃圾收集線程還沒有進行垃圾收集,包含雇員檔案信息的對象仍然完好地保存在內存中,應用程序也要重新構建一個對象。我們知道,訪問磁盤文件、訪問網絡資源、查詢數據庫等操作都是影響應用程序執行性能的重要因素,如果能重新獲取那些尚未被回收的Java對象的引用,必將減少不必要的訪問,大大提高程序的運行速度。

2 如果使用軟引用
SoftReference的特點是它的一個實例保存對一個Java對象的軟引用,該軟引用的存在不妨礙垃圾收集線程對該Java對象的回收。也就是說,一旦SoftReference保存了對一個Java對象的軟引用後,在垃圾線程對這個Java對象回收前,SoftReference類所提供的get()方法返回Java對象的強引用。另外,一旦垃圾線程回收該Java對象之後,get()方法將返回null。
看下面代碼:

MyObject aRef = new
MyObject();

SoftReference aSoftRef=new SoftReference(aRef);
此時,對於這個MyObject對象,有兩個引用路徑,一個是來自SoftReference對象的軟引用,一個來自變量aReference的強引用,所以這個MyObject對象是強可及對象。
隨即,我們可以結束aReference對這個MyObject實例的強引用:

aRef = null;

此後,這個MyObject對象成為了軟可及對象。如果垃圾收集線程進行內存垃圾收集,並不會因為有一個SoftReference對該對象的引用而始終保留該對象。Java虛擬機的垃圾收集線程對軟可及對象和其他一般Java對象進行了區別對待:軟可及對象的清理是由垃圾收集線程根據其特定算法按照內存需求決定的。也就是說,垃圾收集線程會在虛擬機拋出OutOfMemoryError之前回收軟可及對象,而且虛擬機會盡可能優先回收長時間閑置不用的軟可及對象,對那些剛剛構建的或剛剛使用過的“新”軟可反對象會被虛擬機盡可能保留。在回收這些對象之前,我們可以通過:
MyObject anotherRef=(MyObject)aSoftRef.get();
重新獲得對該實例的強引用。而回收之後,調用get()方法就只能得到null了。

3 使用ReferenceQueue清除失去了軟引用對象的SoftReference
作為一個Java對象,SoftReference對象除了具有保存軟引用的特殊性之外,也具有Java對象的一般性。所以,當軟可及對象被回收之後,雖然這個SoftReference對象的get()方法返回null,但這個SoftReference對象已經不再具有存在的價值,需要一個適當的清除機制,避免大量SoftReference對象帶來的內存泄漏。在java.lang.ref包裏還提供了ReferenceQueue。如果在創建SoftReference對象的時候,使用了一個ReferenceQueue對象作為參數提供給SoftReference的構造方法,如:

ReferenceQueue queue = new
ReferenceQueue();

SoftReference
ref=new
SoftReference(aMyObject, queue);
那麽當這個SoftReference所軟引用的aMyOhject被垃圾收集器回收的同時,ref所強引用的SoftReference對象被列入ReferenceQueue。也就是說,ReferenceQueue中保存的對象是Reference對象,而且是已經失去了它所軟引用的對象的Reference對象。另外從ReferenceQueue這個名字也可以看出,它是一個隊列,當我們調用它的poll()方法的時候,如果這個隊列中不是空隊列,那麽將返回隊列前面的那個Reference對象。
在任何時候,我們都可以調用ReferenceQueue的poll()方法來檢查是否有它所關心的非強可及對象被回收。如果隊列為空,將返回一個null,否則該方法返回隊列中前面的一個Reference對象。利用這個方法,我們可以檢查哪個SoftReference所軟引用的對象已經被回收。於是我們可以把這些失去所軟引用的對象的SoftReference對象清除掉。常用的方式為:

SoftReference ref = null;

while ((ref = (EmployeeRef) q.poll()) != null) {

// 清除ref

}

技術分享圖片
package com.zwj.tree;
import java.lang.ref.WeakReference;

/**
 * 引用分類:強、軟、弱、虛
 * 強與弱引用
 * @author Administrator
 *
 */
public class RefDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //字符串常量池 
        String str =new String("bjsxt is very good");
        //弱引用 管理 對象
        WeakReference<String> wr =new WeakReference<String>(str);
        System.out.println("gc運行前:"+wr.get());
        //斷開引用
        str =null;
        //通知回收
        System.gc();
        System.runFinalization();
        //對象被回收
        System.out.println("gc運行後:"+wr.get()); 
        /*gc運行前:bjsxt is very good
          gc運行後:null
        */
    }
    public static void testStrong(){
        //字符串常量池  共享(不能回收)
        String str ="bjsxt is very good";
        //弱引用 管理 對象
        WeakReference<String> wr =new WeakReference<String>(str);
        System.out.println("gc運行前:"+wr.get());
        //斷開引用
        str =null;
        //通知回收
        System.gc();
        System.runFinalization();
        System.out.println("gc運行後:"+wr.get());
        /*
         gc運行前:bjsxt is very good
         gc運行後:bjsxt is very good*/
    }

}
WeakReference new String()管理的字符串將回收 技術分享圖片
package com.zwj.tree;
import java.util.WeakHashMap;

/**
 * WeakHashMap 鍵為弱類型,gc運行立即回收
 * @author Administrator
 *
 */
public class WeakHashMapDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        WeakHashMap<String,String> map =new WeakHashMap<String,String>();
        //測試數據
        //常量池對象,不會回收
        map.put("abc", "a");
        map.put("d", "test");
        //gc運行 已被回收
        map.put(new String("bjsxt"), "c");
        map.put(new String("dsf"), "d");
        
        //通知回收
        System.gc();
        System.runFinalization();
        
        System.out.println(map.size());//2個
    }

}
WeakHashMap 鍵為弱類型,gc運行立即回收 技術分享圖片
package com.zwj.tree;
import java.util.HashMap;
import java.util.IdentityHashMap;

/**
 * IdentityHashMap 鍵比較地址去重
 * @author Administrator
 *
 */
public class IdentityHashMapDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        IdentityHashMap<String ,String> map =new IdentityHashMap<String,String>();
        //HashMap<String ,String> map=new HashMap<String ,String>(); //1 和1
        //常量池中的"a"
        map.put("a", "a1");
        map.put("a", "a2");
        System.out.println(map.size());
        map.put(new String("a"), "a3");
        map.put(new String("a"), "a4");
        System.out.println(map.size());
        //1  3
        

    }

}
IdentityHashMap 鍵比較地址去重 技術分享圖片
package com.zwj.tree;

import java.util.EnumMap;


/**
 * EnumMap要求鍵為枚舉
 * @author Administrator
 *
 */
public class EnumMapDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        EnumMap<Season,String> map =new EnumMap<Season,String>(Season.class);
        //存放值
        map.put(Season.SPRING, "春困");
        map.put(Season.SUMMER, "夏無力");
        map.put(Season.AUTUMN, "秋乏");
        map.put(Season.WINTER, "冬眠");
        
        System.out.println(map.size());
        
    }

}
//季節
enum Season{
    SPRING,SUMMER,AUTUMN,WINTER
}
EnumMap要求鍵為枚舉

(4)

一、同步控制:多線程並發訪問集合的線程安全。
常用容器 ArrayList HashSet HashMap 等都是線程不安全的
Collections提供了synchronizedXxx()方法,將指定容器包裝成同步
synchronizedList()
synchronizedSet()
synchronizedMap()

技術分享圖片
package com.bjsxt.others.synread;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 使用Collections管理同步 容器
 * synchronizedList()
    synchronizedSet()
    synchronizedMap()

 * @author Administrator
 *
 */
public class Demo01 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        List<String> list =new ArrayList<String>();
        list.add("a");
        list.add("b");
        //list可以同步
        List<String> synList =Collections.synchronizedList(list);
        System.out.println("線程安全的list制作完畢");
    }

}
使用Collections管理同步容器 線程不安全編程安全


二、不可變設置:“只讀”訪問, Collections提供了三種方法
emptyXxx() 空的不可變的集合
singletonXxx() 一個元素不可變的集合
unmodifiableXxx() 不可變容器

java基礎--集合框架(強弱)