單例模式的終結者——setAccessible(true),setaccessibletrue
先來看下“傳統”的單例模式
package go.derek;public class Singleton{public static int times;private Singleton(){//構造器被調用的時候會列印出次數System.out.println("單例構造器被調用"+(++times)+"兩次");}private final static Singleton instance=new Singleton();public static Singleton getInstance(){return instance;}public void doSomething(){System.out.println("do something");}}下面是測試類別主函數:
package go.derek;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;public class Test {public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {//通過單例模式獲得單例對象obj1Singleton obj1=Singleton.getInstance();//執行一次doSomething方法obj1.doSomething();//觀察控制台,這次獲得的obj2對象跟obj1是同一個單例,沒有調用構造器Singleton obj2=Singleton.getInstance();obj2.doSomething();//下面厲害的來了,首先拿到萬能的Class對象Class<Singleton> clazz=Singleton.class;//然後拿到構造器,使用這個方法私人的構造器也可以拿到Constructor<Singleton> c=clazz.getDeclaredConstructor();//設定在使用構造器的時候不執行許可權檢查c.setAccessible(true);//由於沒有了許可權檢查,所以在Singleton類外面也可以建立對象了,然後執行方法//觀察控制台,私人構造器又被調用了一次,單例模式被攻陷了,執行方法成功。c.newInstance().doSomething();}}
運行結果如下:
單例構造器被調用1兩次
do something
do something
單例構造器被調用2兩次
do something
試想一下,如果某個惡意用戶端通過上面的方式,就可以為所欲為了,所以為了避免出現這種情況,可以再構造器被第二次調用的時候拋出一個異常
package go.derek;public class Singleton{public static int times;private Singleton() {//構造器被調用的時候會列印出次數System.out.println("單例構造器被調用"+(++times)+"兩次");if(instance!=null){throw new IllegalArgumentException("單例構造器不能重複使用");}}private final static Singleton instance=new Singleton();public static Singleton getInstance(){return instance;}public void doSomething(){System.out.println("do something");}}運行結果如下:
單例構造器被調用1兩次
do something
do something
單例構造器被調用2兩次
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at go.derek.Test.main(Test.java:24)
Caused by: java.lang.IllegalArgumentException: 單例構造器不能重複使用
at go.derek.Singleton.<init>(Singleton.java:10)
... 5 more
目的達到了~
私人的靜態方法setAccessible中的解釋
這個主要是利用反射機制調整目標對象的存取權限的時候用到。
這個方法裡就是利用AccessController類,以特權方式去執行AccessibleObject裡面一層的setAccessible函數。因為這一層函數內會利用checkPermission最終到BasicPermission去檢查許可權。
百度手機開發提供的例子BMapApiDemo怎一運行就出錯
android使用自訂UncaughtExceptionHandler 處理常式崩潰
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Properties;
import java.util.TreeSet;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
/**
* UncaughtException處理類,當程式發生Uncaught異常的時候,有該類 來接管程式,並記錄 發送錯誤報表.. 註冊方式
* CrashHandler crashHandler = CrashHandler.getInstance(); //註冊crashHandler
* crashHandler.init(getApplicationContext()); //發送以前沒發送的報告(可選)
* crashHandler.sendPreviousReportsToServer();
*
*/
public class CrashHandler implements UncaughtExceptionHandler {
/** Debug Log tag */
public static final String TAG = "CrashHandler";
/**
* 是否開啟日誌輸出,在Debug狀態下開啟, 在Release狀態下關閉以提示程式效能
* */
public static final boolean DEBUG = true;
/** 系統預設的UncaughtException處理類 */
private Thread.UncaughtExceptionHandler mDefaultHandler;
/** CrashHandler執行個體 */
private static CrashHandler INSTANCE;
/** 程式的Context對象 */
private Context mContext;
/** 使用Properties......餘下全文>>