1. 程式人生 > 實用技巧 >Java反射全解析(使用、原理、問題、在Android中的應用)

Java反射全解析(使用、原理、問題、在Android中的應用)

單例模式

簡介

保證在記憶體中只有一個例項

餓漢式

public class Single01 {
    //類載入初始話
    private static final Single01 INSTANCE = new Single01();
    //私有構造器
    private Single01(){

    }
    //公開方法
    public static Single01 getInstance(){
        return INSTANCE;
    }

    public static void main(String[] args) {
        Single01 instance01 = Single01.getInstance();
        Single01 instance02 = Single01.getInstance();

        System.out.println(instance01 == instance02);
    }
}

反射破解

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Single01 {
    //類載入初始話
    private static final Single01 INSTANCE = new Single01();
    //私有構造器
    private Single01(){

    }
    //公開方法
    public static Single01 getInstance(){
        return INSTANCE;
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Single01 instance01 = Single01.getInstance();
        //獲得class檔案
        Class<Single01> single01Class = Single01.class;
        //獲取無參構造器
        Constructor<Single01> constructor = single01Class.getDeclaredConstructor();
        //暴力反射
        constructor.setAccessible(true);
        //反射例項
        Single01 single01 = constructor.newInstance();

        System.out.println(single01 == instance01);

    }
}

懶漢式

執行緒安全問題

/**
 * lazy load
 * 雖然按需求初始話,但是有執行緒安全的問題
 * 這裡要加上volatile  防止指令重排
 */
public class Single02 {

    private static Single02 INSTANCE;

    private Single02(){

    }

    public static Single02 getINSTANCE(){
        if (INSTANCE == null){
            try {
                //測試
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Single02();
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                System.out.println(Single02.getINSTANCE());
            }).start();
        }
    }
}

解決 synchronized

/**
 * lazy load
 * 雖然按需求初始話,但是有執行緒安全的問題
 *  加上 synchronized 效率會下降
 */
public class Single02 {

    private static Single02 INSTANCE;

    private Single02(){

    }

    public synchronized static Single02 getINSTANCE(){
        if (INSTANCE == null){
            try {
                //測試
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Single02();
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                System.out.println(Single02.getINSTANCE());
            }).start();
        }
    }
}

雙重檢測鎖

/**
 * 雙重檢測鎖
 */
public class Single03 {

    private static Single03 INSTANCE;

    private Single03(){

    }

    public static Single03 getINSTANCE(){
        if (INSTANCE == null){
          synchronized (Single03.class){
              if (INSTANCE == null){
                  try {
                      //測試
                      Thread.sleep(1);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  INSTANCE = new Single03();
              }
          }
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                System.out.println(Single03.getINSTANCE());
            }).start();
        }
    }
}

反射破解

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Single04 {
    private static Single04 INSTANCE;

    private Single04(){

    }

    public static Single04 getINSTANCE(){
        if (INSTANCE == null){
            synchronized (Single04.class){
                if (INSTANCE == null){
                    try {
                        //測試
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Single04();
                }
            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Single04 instance01 = Single04.getINSTANCE();
        
        Class<Single04> single04Class = Single04.class;
        Constructor<Single04> constructor = single04Class.getDeclaredConstructor();

        constructor.setAccessible(true);

        Single04 single04 = constructor.newInstance();

        System.out.println(single04 == instance01);
    }
}

靜態內部類

//開始實現懶載入
public class Single05 {
    private Single05(){

    }

    private static class HolderSingle05{
        private static final Single05 INSTANCE = new Single05();
    }
    //公開方法
    public static Single05 getInstance(){
        return HolderSingle05.INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(Single05.getInstance());
            }).start();
        }
    }
}

反射破解

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Single05 {
    private Single05(){

    }
	//匿名內部類
    private static class HolderSingle05{
        private static final Single05 INSTANCE = new Single05();
    }
    //公開方法
    public static Single05 getInstance(){
        return HolderSingle05.INSTANCE;
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Single05 instance = Single05.getInstance();

        Class<Single05> single05Class = Single05.class;

        Constructor<Single05> declaredConstructor = single05Class.getDeclaredConstructor();

        declaredConstructor.setAccessible(true);

        Single05 single05 = declaredConstructor.newInstance();

        System.out.println(single05 == instance);
    }
}

列舉 enum

//列舉類
public enum Single06 {
    INSTANCE;

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Single06.INSTANCE.hashCode());
        }
    }
}

反射破解

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

//列舉類
public enum Single06 {
    INSTANCE;

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        System.out.println(Single06.INSTANCE.hashCode());


        Class<Single06> single06Class = Single06.class;;
        Constructor<Single06> declaredConstructor = single06Class.getDeclaredConstructor();

        declaredConstructor.setAccessible(true);

        Single06 single06 = declaredConstructor.newInstance();
        System.out.println(single06.hashCode());
    }
}

丟擲異常 沒有空參構造

這裡可以看到如果是列舉的話會報Cannot reflectively create enum objects

通過反編譯可以看到構造器其實是有引數的

重新執行一下

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

//列舉類
public enum Single06 {
    INSTANCE;

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        System.out.println(Single06.INSTANCE.hashCode());


        Class<Single06> single06Class = Single06.class;;
        //在構造器傳入指定引數
        Constructor<Single06> declaredConstructor = single06Class.getDeclaredConstructor(String.class,int.class);

        declaredConstructor.setAccessible(true);

        Single06 single06 = declaredConstructor.newInstance();
        System.out.println(single06.hashCode());
    }
}

丟擲指定異常 It's ok