欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java/Android引用類型及其使用全面分析

 更新時間:2016年09月21日 07:16:16   投稿:jingxian  
下面小編就為大家?guī)硪黄狫ava/Android引用類型及其使用全面分析。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

Java/Android中有四種引用類型,分別是:

Strong reference - 強引用
Soft Reference - 軟引用
Weak Reference - 弱引用
Phantom Reference - 虛引用

不同的引用類型有著不同的特性,同時也對應(yīng)著不同的使用場景。

1.Strong reference - 強引用

實際編碼中最常見的一種引用類型。常見形式如:A a = new A();等。強引用本身存儲在棧內(nèi)存中,其存儲指向?qū)?nèi)存中對象的地址。一般情況下,當對內(nèi)存中的對象不再有任何強引用指向它時,垃圾回收機器開始考慮可能要對此內(nèi)存進行的垃圾回收。如當進行編碼:a = null,此時,剛剛在堆中分配地址并新建的a對象沒有其他的任何引用,當系統(tǒng)進行垃圾回收時,堆內(nèi)存將被垃圾回收。

SoftReference、WeakReference、PhantomReference都是類java.lang.ref.Reference的子類。Reference作為抽象基類,定義了其子類對象的基本操作。Reference子類都具有如下特點:

1.Reference子類不能無參化直接創(chuàng)建,必須至少以強引用對象為構(gòu)造參數(shù),創(chuàng)建各自的子類對象;
2.因為1中以強引用對象為構(gòu)造參數(shù)創(chuàng)建對象,因此,使得原本強引用所指向的堆內(nèi)存中的對象將不再只與強引用本身直接關(guān)聯(lián),與Reference的子類對象的引用也有一定聯(lián)系。且此種聯(lián)系將可能影響到對象的垃圾回收。

根據(jù)不同的子類對象對其指示對象(強引用所指向的堆內(nèi)存中的對象)的垃圾回收不同的影響特點,分別形成了三個子類,即SoftReference、WeakReference和PhantomReference。

2.Soft Reference - 軟引用

軟引用的一般使用形式如下:
A a = new A();
SoftReference<A> srA = new SoftReference<A>(a);

通過對象的強引用為參數(shù),創(chuàng)建了一個SoftReference對象,并使棧內(nèi)存中的wrA指向此對象。

此時,進行如下編碼:a = null,對于原本a所指向的A對象的垃圾回收有什么影響呢?

先直接看一下下面一段程序的輸出結(jié)果:

import java.lang.ref.SoftReference;

public class ReferenceTest {

  public static void main(String[] args) {

    A a = new A();
    
    SoftReference<A> srA = new SoftReference<A>(a);

    a = null;

    if (srA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + srA.get());
    }

    // 垃圾回收
    System.gc();

    if (srA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + srA.get());
    }

  }
}

class A {

}

##輸出結(jié)果為:

1 a對象尚未被回收A@4807ccf6
2 a對象尚未被回收A@4807ccf6

當 a = null后,堆內(nèi)存中的A對象將不再有任何的強引用指向它,但此時尚存在srA引用的對象指向A對象。當?shù)谝淮握{(diào)用srA.get()方法返回此指示對象時,由于垃圾回收器很有可能尚未進行垃圾回收,此時get()是有結(jié)果的,這個很好理解。當程序執(zhí)行System.gc();強制垃圾回收后,通過srA.get(),發(fā)現(xiàn)依然可以得到所指示的A對象,說明A對象并未被垃圾回收。那么,軟引用所指示的對象什么時候才開始被垃圾回收呢?需要滿足如下兩個條件:

1.當其指示的對象沒有任何強引用對象指向它;

2.當虛擬機內(nèi)存不足時。

因此,SoftReference變相的延長了其指示對象占據(jù)堆內(nèi)存的時間,直到虛擬機內(nèi)存不足時垃圾回收器才回收此堆內(nèi)存空間。

3.Weak Reference - 弱引用

同樣的,軟引用的一般使用形式如下:

A a = new A();
WeakReference<A> wrA = new WeakReference<A>(a);

當沒有任何強引用指向此對象時, 其垃圾回收又具有什么特性呢?

import java.lang.ref.WeakReference;

public class ReferenceTest {

  public static void main(String[] args) {

    A a = new A();

    WeakReference<A> wrA = new WeakReference<A>(a);

    a = null;

    if (wrA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + wrA.get());
    }

    // 垃圾回收
    System.gc();

    if (wrA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + wrA.get());
    }

  }

}

class A {

}

##輸出結(jié)果為:

a對象尚未被回收A@52e5376a
a對象進入垃圾回收流程

輸出的第一條結(jié)果解釋同上。當進行垃圾回收后,wrA.get()將返回null,表明其指示對象進入到了垃圾回收過程中。因此,對弱引用特點總結(jié)為:

WeakReference不改變原有強引用對象的垃圾回收時機,一旦其指示對象沒有任何強引用對象時,此對象即進入正常的垃圾回收流程。

那么,依據(jù)此特點,很可能有疑問:WeakReference存在又有什么意義呢?

其主要使用場景見于:當前已有強引用指向強引用對象,此時由于業(yè)務(wù)需要,需要增加對此對象的引用,同時又不希望改變此引用的垃圾回收時機,此時WeakReference正好符合需求,常見于一些與生命周期的場景中。

下面給出一個Android中關(guān)于WeakReference使用的場景 —— 結(jié)合靜態(tài)內(nèi)部類和WeakReference來解決Activity中可能存在的Handler內(nèi)存泄露問題。

Activity中我們需要新建一個線程獲取數(shù)據(jù),使用handler - sendMessage方式。下面是這一過程的一般性代碼:

public class MainActivity extends Activity {

  //...
  private int page;
  private Handler handler = new Handler() {

    @Override
    public void handleMessage(Message msg) {
      if (msg.what == 1) {

        //...

        page++;
      } else {

        //...

      }

    };
  };

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //...

    new Thread(new Runnable() {
      @Override
      public void run() {
        //.. 
        Message msg = Message.obtain();
        msg.what = 1;
        //msg.obj = xx;
        handler.sendMessage(msg);
      }
    }).start();

    //...

  }

}

在Eclispe中Run Link,將會看到警示信息:This Handler class should be static or leaks might occur ...點擊查看此信息,其詳情中對問題進行了說明并給出了建議性的解決方案。

Issue: Ensures that Handler classes do not hold on to a reference to an outer class
Id: HandlerLeak

Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class;In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.

大致的意思是建議將Handler定義成內(nèi)部靜態(tài)類,并在此靜態(tài)內(nèi)部類中定義一個WeakReference的引用,由于指示外部的Activity對象。

問題分析:

Activity具有自身的生命周期,Activity中新開啟的線程運行過程中,可能此時用戶按下了Back鍵,或系統(tǒng)內(nèi)存不足等希望回收此Activity,由于Activity中新起的線程并不會遵循Activity本身的什么周期,也就是說,當Activity執(zhí)行了onDestroy,由于線程以及Handler 的HandleMessage的存在,使得系統(tǒng)本希望進行此Activity內(nèi)存回收不能實現(xiàn),因為非靜態(tài)內(nèi)部類中隱性的持有對外部類的引用,導(dǎo)致可能存在的內(nèi)存泄露問題。

因此,在Activity中使用Handler時,一方面需要將其定義為靜態(tài)內(nèi)部類形式,這樣可以使其與外部類(Activity)解耦,不再持有外部類的引用,同時由于Handler中的handlerMessage一般都會多少需要訪問或修改Activity的屬性,此時,需要在Handler內(nèi)部定義指向此Activity的WeakReference,使其不會影響到Activity的內(nèi)存回收同時,可以在正常情況下訪問到Activity的屬性。

Google官方給出的建議寫法為:

public class MainActivity extends Activity {

  //...
  private int page;
  private MyHandler mMyHandler = new MyHandler(this);

  private static class MyHandler extends Handler {

    private WeakReference<MainActivity> wrActivity;

    public MyHandler(MainActivity activity) {
      this.wrActivity = new WeakReference<MainActivity>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
      if (wrActivity.get() == null) {
        return;
      }
      MainActivity mActivity = wrActivity.get();
      if (msg.what == 1) {

        //...
        mActivity.page++;

      } else {

        //...

      }
    }

  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //...

    new Thread(new Runnable() {
      @Override
      public void run() {
        //.. 
        Message msg = Message.obtain();
        msg.what = 1;
        //msg.obj = xx;
        mMyHandler.sendMessage(msg);
      }
    }).start();

    //...

  }

}

對于SoftReference和WeakReference,還有一個構(gòu)造器參數(shù)為ReferenceQueue<T>,當SoftReference或WeakReference所指示的對象確實被垃圾回收后,其引用將被放置于ReferenceQueue中。注意上文中,當SoftReference或WeakReference的get()方法返回null時,僅是表明其指示的對象已經(jīng)進入垃圾回收流程,此時對象不一定已經(jīng)被垃圾回收。而只有確認被垃圾回收后,如果ReferenceQueue,其引用才會被放置于ReferenceQueue中。

看下面的一個例子:

public class ReferenceTest {

  public static void main(String[] args) {

    A a = new A();

    WeakReference<A> wrA = new WeakReference<A>(a);

    a = null;

    if (wrA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + wrA.get());
    }

    // 垃圾回收
    System.gc();

    if (wrA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + wrA.get());
    }

  }
}

class A {

  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    System.out.println("in A finalize");
  }

}

##輸出結(jié)果為:

1 a對象尚未被回收A@46993aaa
2 a對象被回收
3 in A finalize

由此,也驗證了上文中的“進入垃圾回收流程”的說法。下面結(jié)合ReferenceQueue,看一段代碼:

public class ReferenceTest {

  public static void main(String[] args) {

    A a = new A();

    ReferenceQueue<A> rq = new ReferenceQueue<A>();
    WeakReference<A> wrA = new WeakReference<A>(a, rq);

    a = null;

    if (wrA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + wrA.get());
    }

    System.out.println("rq item:" + rq.poll());

    // 垃圾回收
    System.gc();

    if (wrA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + wrA.get());
    }

    /*
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    */

    System.out.println("rq item:" + rq.poll());

  }
}

class A {

  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    System.out.println("in A finalize");
  }

}

##輸出結(jié)果為:

a對象尚未被回收A@302b2c81
rq item:null
a對象進入垃圾回收流程
rq item:null
in A finalize

由此,驗證了“僅進入垃圾回收流程的SoftReference或WeakReference引用尚未被加入到ReferenceQueue”。


public class ReferenceTest {

  public static void main(String[] args) {

    A a = new A();

    ReferenceQueue<A> rq = new ReferenceQueue<A>();
    WeakReference<A> wrA = new WeakReference<A>(a, rq);

    a = null;

    if (wrA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + wrA.get());
    }

    System.out.println("rq item:" + rq.poll());

    // 垃圾回收
    System.gc();

    if (wrA.get() == null) {
      System.out.println("a對象進入垃圾回收流程");
    } else {
      System.out.println("a對象尚未被回收" + wrA.get());
    }

    try {
      Thread.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    System.out.println("rq item:" + rq.poll());

  }
}

class A {

  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    System.out.println("in A finalize");
  }

}

##輸出結(jié)果為:

a對象尚未被回收A@6276e1db
rq item:null
a對象進入垃圾回收流程
in A finalize
rq item:java.lang.ref.WeakReference@645064f

由此,證實了上述說法。

4.PhantomReference

與SoftReference或WeakReference相比,PhantomReference主要差別體現(xiàn)在如下幾點:

1.PhantomReference只有一個構(gòu)造函數(shù)PhantomReference(T referent, ReferenceQueue<? super T> q),因此,PhantomReference使用必須結(jié)合ReferenceQueue;

2.不管有無強引用指向PhantomReference的指示對象,PhantomReference的get()方法返回結(jié)果都是null。

public class ReferenceTest {

  public static void main(String[] args) {

    A a = new A();

    ReferenceQueue<A> rq = new ReferenceQueue<A>();
    PhantomReference<A> prA = new PhantomReference<A>(a, rq);

    System.out.println("prA.get():" + prA.get());
    
    a = null;
    
    System.gc();
    
    try {
      Thread.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    System.out.println("rq item:" + rq.poll());

  }
}

class A {

}

##輸出結(jié)果為:

prA.get():null
rq item:java.lang.ref.PhantomReference@1da12fc0

代碼中的Thread.sleep(1);作用與上例中相同,都是確保垃圾回收線程能夠執(zhí)行。否則,進進入垃圾回收流程而沒有真正被垃圾回收的指示對象的虛引用是不會被加入到PhantomReference中的。

與WeakReference相同,PhantomReference并不會改變其指示對象的垃圾回收時機。且可以總結(jié)出:ReferenceQueue的作用主要是用于監(jiān)聽SoftReference/WeakReference/PhantomReference的指示對象是否已經(jīng)被垃圾回收。

以上就是小編為大家?guī)淼腏ava/Android引用類型及其使用全面分析的全部內(nèi)容了,希望對大家有所幫助,多多支持腳本之家~

相關(guān)文章

  • 淺談Java由于不當?shù)膱?zhí)行順序?qū)е碌乃梨i

    淺談Java由于不當?shù)膱?zhí)行順序?qū)е碌乃梨i

    為了保證線程的安全,我們引入了加鎖機制,但是如果不加限制的使用加鎖,就有可能會導(dǎo)致順序死鎖(Lock-Ordering Deadlock)。本文將會討論一下順序死鎖的問題。
    2021-06-06
  • Spring?MVC項目中的異常處理詳解

    Spring?MVC項目中的異常處理詳解

    在Web開發(fā)中 我們經(jīng)常會需要處理各種異常,這篇文章主要給大家介紹了關(guān)于Spring?MVC項目中異常處理的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-06-06
  • Springboot整合quartz產(chǎn)生錯誤及解決方案

    Springboot整合quartz產(chǎn)生錯誤及解決方案

    這篇文章主要介紹了Springboot整合quartz產(chǎn)生錯誤及解決方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • Mybatis通過Spring完成代理類注入的流程分析

    Mybatis通過Spring完成代理類注入的流程分析

    這篇文章主要介紹了Mybatis通過Spring完成代理類注入的流程分析,本文通過實例圖文相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • mybatis-plus 攔截器敏感字段加解密的實現(xiàn)

    mybatis-plus 攔截器敏感字段加解密的實現(xiàn)

    數(shù)據(jù)庫在保存數(shù)據(jù)時,對于某些敏感數(shù)據(jù)需要脫敏或者加密處理,本文主要介紹了mybatis-plus 攔截器敏感字段加解密的實現(xiàn),感興趣的可以了解一下
    2021-11-11
  • Java舉例講解分治算法思想

    Java舉例講解分治算法思想

    分治算法的基本思想是將一個規(guī)模為N的問題分解為K個規(guī)模較小的子問題,這些子問題相互獨立且與原問題性質(zhì)相同。求出子問題的解,就可得到原問題的解,本篇文章我們就用分治算法來實現(xiàn)歸并排序快速排序以及二分搜索算法
    2022-04-04
  • Java/Web調(diào)用Hadoop進行MapReduce示例代碼

    Java/Web調(diào)用Hadoop進行MapReduce示例代碼

    本篇文章主要介紹了Java/Web調(diào)用Hadoop進行MapReduce示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • springboot利用AOP完成日志統(tǒng)計的詳細步驟

    springboot利用AOP完成日志統(tǒng)計的詳細步驟

    項目用到了過濾器,可能有的人會不理解,之所以用過濾器是因為想要在日志記錄post請求的json數(shù)據(jù)。本文重點給大家介紹springboot利用AOP完成日志統(tǒng)計的詳細步驟,感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • Java快速排序的實現(xiàn)方法示例

    Java快速排序的實現(xiàn)方法示例

    快速排序是對冒泡排序的一種改進,下面這篇文章主要給大家介紹了關(guān)于Java快速排序的實現(xiàn)方法,文中通過代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-03-03
  • java中SynchronizedList和Vector的區(qū)別詳解

    java中SynchronizedList和Vector的區(qū)別詳解

    這篇文章主要介紹了java中SynchronizedList和Vector的區(qū)別詳解,Vector是java.util包中的一個類。 SynchronizedList是java.util.Collections中的一個靜態(tài)內(nèi)部類。,需要的朋友可以參考下
    2019-06-06

最新評論