1. 程式人生 > 實用技巧 >JavaSE學習筆記 - 反射技術

JavaSE學習筆記 - 反射技術

概述

  • 反射是一種強大的工具,可以用來編寫能夠動態操縱 Java 程式碼的程式,通過反射機制我們可以操作位元組碼檔案。反射機制將類的各個部分封裝成了物件,在程式執行的過程中我們可以操作這些物件(在操作一個類物件的時候我們可以操作其方法成員變數等)。這樣可以使得程式解耦,提高了程式的可擴充套件性。

Java 程式碼的三個階段

  • 原始碼階段:編寫類檔案,然後新增成員變數,成員方法等,程式碼編譯後生成位元組碼檔案,此時程式碼還未被載入進記憶體。
  • Class 類物件階段:Class 類物件使用類載入器將位元組碼檔案載入進記憶體,此時記憶體中就會產生一個唯一的 Class 類物件來標識這個類中的各項資訊,Class 類物件中又包含了描述成員變數的 Field 物件、描述構造方法的 Constructor 物件和描述成員方法的 Method 物件。
  • 執行時階段:new 一個新的類物件。

Class

  • 在程式執行的時候,系統始終為所有的物件維護一個執行時的型別標識,這個資訊會跟蹤每一個物件所屬的類,我們使用 Java 中的 Class 類就可以訪問這些被記錄的資訊。

獲取 Class 物件的三種方式

  • Class.forName("全類名"):將位元組碼檔案載入進記憶體,配置檔案常用
public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        Class cls = Class.forName("java.lang.String");
        System.out.println(cls);//class java.lang.String
    }
}
  • 類名.class:常用於引數的傳遞
public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        Class cls = Class.forName("java.lang.String");
        Class cls1 = String.class;
        System.out.println(cls.hashCode());//460141958
        System.out.println(cls1);//class java.lang.String
    }
}
  • 物件.getClass():常用於獲取物件位元組碼
public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        Class cls = Class.forName("java.lang.String");
        Class cls1 = String.class;
        String str = "";
        Class cls2 = str.getClass();
        //位元組碼檔案在記憶體中只被載入一次
        //不管使用什麼方式獲取到的Class物件都是同一個
        System.out.println(cls.hashCode());//460141958
        System.out.println(cls1.hashCode());//460141958
        System.out.println(cls2);//class java.lang.String
    }
}

Class 類常用 API

  • 獲取 public 修飾的成員變數
//獲取 public 修飾的成員變數
public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class cls = Class.forName("java.lang.String");
        Field[] fields = cls.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }

        Field field = cls.getField("CASE_INSENSITIVE_ORDER");
        System.out.println(field.getName());
    }
}


//獲取所有的成員變數
public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class cls = Class.forName("java.lang.String");
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }

        Field field = cls.getDeclaredField("hash");
        System.out.println(field.getName());
    }
}
  • 獲取建構函式
public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("java.lang.String");

        //得到所有公共的建構函式物件
        Constructor[] constructors = cls.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        //得到特定的公共建構函式物件
        Constructor constructor = cls.getConstructor(String.class);
        System.out.println(constructor);
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("java.lang.String");

        //得到所有的建構函式物件
        Constructor[] constructors = cls.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        //得到特定的建構函式物件
        Constructor constructor = cls.getDeclaredConstructor(String.class);
        System.out.println(constructor);
    }
}
  • 獲取成員方法
public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("java.lang.String");

        //獲取所有公共的成員方法
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        //獲取特定的公共的成員方法
        System.out.println("-------");
        Method method = cls.getMethod("toLowerCase", Locale.class);
        System.out.println(method);
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("java.lang.String");

        //獲取所有的成員方法
        Method[] methods = cls.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        //獲取特定的成員方法
        System.out.println("-------");
        Method method = cls.getDeclaredMethod("lastIndexOfSupplementary", int.class, int.class);
        System.out.println(method);
    }
}
  • 有關 Class 類的 API
public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("java.lang.String");

        System.out.println(cls.getName());//java.lang.String
        System.out.println(cls.getSimpleName());//String

        //獲取父類
        Class superclass = cls.getSuperclass();
        System.out.println(superclass);//class java.lang.Object
        System.out.println(superclass.isInterface());//false

        //獲取包物件
        Package aPackage = cls.getPackage();
        System.out.println(aPackage.getName());//java.lang

    }
}

Constructor

public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("java.lang.String");

        //得到所有的建構函式物件
        Constructor[] constructors = cls.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
            //方法名
            System.out.println(constructor.getName());
            //修飾符
            System.out.println(Modifier.toString(constructor.getModifiers()));
            //引數型別
            Class[] parameterTypes = constructor.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.print(parameterType.getName() + " ");
            }
            System.out.println();
            System.out.println("-------------------------------------");
        }
    }
}


//建立物件
public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = String.class;
        String str = (String) cls.newInstance();
    }
}

Field

public class Main {
    public static void main(String[] args) throws Exception {
        String str = "1111";
        Class cls = Class.forName("java.lang.String");
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
            System.out.println(Modifier.toString(field.getModifiers()));
            System.out.println(field.getType().getSimpleName());
            System.out.println(field.getName());
            //System.out.println(field.get(str));
            System.out.println("-----------------------------------------------");
        }

    }
}
//為物件的成員變數設定值
public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = String.class;
        String str = (String) cls.newInstance();
        Field field = cls.getDeclaredField("value");
        //不是公共的成員變數是需要暴力反射,預設只能修改非公共成員變數
        field.setAccessible(true);
        System.out.println(field);
        System.out.println(field.get(str));//[C@4554617c
        System.out.println(str);//
        field.set(str, new char[]{'1', '1'});
        System.out.println(field.get(str));//[C@74a14482
        System.out.println(str);//11
    }
}

Method

public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("java.lang.String");

        //獲取所有的成員方法
        Method[] methods = cls.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
            System.out.println(Modifier.toString(method.getModifiers()));
            System.out.println(method.getReturnType().getSimpleName());
            Class<?>[] parameterTypes = method.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println(parameterType.getSimpleName());
            }
            //是否有可變引數
            System.out.println(method.isVarArgs());
            System.out.println(method.getName());
            System.out.println("-------------------------");
        }
    }
}

//執行類方法
public class Main {
    public static void main(String[] args) throws Exception {
        Class cls = String.class;
        String str = (String) cls.newInstance();
        Field field = cls.getDeclaredField("value");
        field.setAccessible(true);

        field.set(str, new char[]{'1', '1'});

        Method method = cls.getDeclaredMethod("length");
        System.out.println(method.invoke(str));

    }
}

配置檔案操作類

配置檔案

className = java.lang.String
methodName = length
fieldName = value

Properties + IO + 反射

public class Main {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();

        //方式一:利用當前類獲取流,配置檔案需要在src目錄下
        ClassLoader classLoader = Main.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        properties.load(is); //要記得關閉流

        //方式二:首先獲取檔案路徑,然後根據路徑建立輸入流
        //配置檔案需要在根路徑下
//        String path = Thread.currentThread().getContextClassLoader().getResource("pro.properties").getPath();
//        //System.out.println(path);
//        FileReader reader = new FileReader(path);
//        properties.load(reader);

        Class cls = Class.forName(properties.getProperty("className"));
        Object o = cls.newInstance();
        Field field = cls.getDeclaredField(properties.getProperty("fieldName"));
        field.setAccessible(true);
        field.set(o, new char[]{'a', 'b'});
        System.out.println(field.get(o));

        Method method = cls.getDeclaredMethod(properties.getProperty("methodName"));
        System.out.println(method.invoke(o));
    }
}

ResourceBundle + 反射

public class Main {
    public static void main(String[] args) throws Exception {
        //資源繫結器,配置檔案需要放在根路徑下
        ResourceBundle bundle = ResourceBundle.getBundle("pro");

        Class cls = Class.forName(bundle.getString("className"));
        Object o = cls.newInstance();
        Field field = cls.getDeclaredField(bundle.getString("fieldName"));
        field.setAccessible(true);
        field.set(o, new char[]{'a', 'b'});
        System.out.println(field.get(o));

        Method method = cls.getDeclaredMethod(bundle.getString("methodName"));
        System.out.println(method.invoke(o));
    }
}

反射方式反編譯類框架

配置檔案

className = java.util.ResourceBundle 

測試程式碼

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        //資源繫結器,配置檔案需要放在根路徑下
        ResourceBundle bundle = ResourceBundle.getBundle("pro");

        Class<?> cls = Class.forName(bundle.getString("className"));
        Package aPackage = cls.getPackage();
        //包
        if (aPackage != null) System.out.println("package " + aPackage.getName());
        System.out.println();
        //修飾符
        System.out.print(Modifier.toString(cls.getModifiers()) + " ");
        //類名
        System.out.print(cls.getSimpleName() + " ");
        //父類
        Class<?> superclass = cls.getSuperclass();
        if (!superclass.equals(Object.class)) {
            System.out.print( "extends " + superclass.getSimpleName() + " ");
        }
        //介面
        Class<?>[] interfaces = cls.getInterfaces();
        StringBuilder _interfaces = new StringBuilder();
        if(interfaces.length == 0) {
            _interfaces.append("");
        } else {
            _interfaces.append(" implements ");
        }
        for (int i = 0; i < interfaces.length; i++) {
            _interfaces.append(interfaces[i].getSimpleName());
            if (i != interfaces.length - 1) {
                _interfaces.append(", ");
            } else {
                _interfaces.append(" ");
            }
        }
        System.out.println(_interfaces + "{");

        System.out.println();
        //獲取成員變數
        getDeclaredFields(cls);
        //獲取構造方法
        getDeclaredConstructors(cls);
        //獲取成員方法
        getMethods(cls);

        System.out.println("}");
    }

    private static void getDeclaredFields(Class<?> cls) {
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            System.out.print("\t");
            //修飾符
            System.out.print(Modifier.toString(field.getModifiers()) + " ");
            //資料型別
            System.out.print(field.getType().getSimpleName() + " ");
            //變數名
            System.out.println(field.getName() + ";");
            //System.out.println(field);
            //System.out.println("----------------");
        }
        System.out.println();
    }

    private static void getDeclaredConstructors(Class<?> cls) {
        Constructor<?>[] constructors = cls.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            //修飾符
            System.out.print("\t");
            if (constructor.getModifiers() != 0)
                System.out.print(Modifier.toString(constructor.getModifiers()) + " ");
            //方法名
            System.out.print(cls.getSimpleName() + "(");
            //引數
            Class<?>[] typeParameters = constructor.getParameterTypes();
            StringBuilder _typeParameters = new StringBuilder();
            for (int i = 0; i < typeParameters.length; i++) {
                if (i != 0) {
                    _typeParameters.append(", ");
                }
                _typeParameters.append(typeParameters[i].getSimpleName());
            }
            System.out.println(_typeParameters + "){};");
            //System.out.println(constructor);
            //System.out.println("---------------------------");
        }
        System.out.println();
    }

    private static void getMethods(Class<?> cls) {
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.print("\t");
            //修飾符
            System.out.print(Modifier.toString(method.getModifiers()) + " ");
            //返回值
            System.out.print(method.getReturnType().getSimpleName() + " ");
            //方法名
            System.out.print(method.getName() + "(");
            //引數
            Class<?>[] parameterTypes = method.getParameterTypes();
            StringBuilder _parameterTypes = new StringBuilder();
            for (int i = 0; i < parameterTypes.length; i++) {
                if (i != 0) {
                    _parameterTypes.append(", ");
                }
                _parameterTypes.append(parameterTypes[i].getSimpleName());
            }
            System.out.println(_parameterTypes + "){};");
            //System.out.println(method);
            //System.out.println("------------------------");
        }
        System.out.println();
    }
}