java反射筆記,自用

  以前的學習筆記,自用的反射筆記,比較雜亂無章,甚在內容全

  JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。

  基礎版:

public class reflection1 {
    public static void main(String[] args) throws Exception {
        Class.forName("xxx");
    }
}

class xxx{
    public xxx(){
        System.out.println("xxx");
    }

    static {
        System.out.println("xxx1");
    }

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

  forName獲取一個類,當運行這段代碼,會動態調用static靜態代碼塊:

 

 

獲取函數方法:

測試代碼塊:

  

public class reflection1 {
    public static void main(String[] args) throws Exception {
        Class clazz=Class.forName("xxx");
        //實例化類,然後調用方法
        clazz.getMethod("hello").invoke(clazz.newInstance());

    }
}

class xxx{
    public xxx(){
        System.out.println("xxx");
    }

    public void hello(){
        System.out.println("hello");
    }

    static {
        System.out.println("xxx1");
    }

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

  執行函數invoke後,會調用類的構造方法,因爲初始化優先級,{}會比構造方法先調用,而方法是最後調用

所以最後的輸出結果是:
  

 

   獲取構造方法:

   

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

public class Reflection {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        Class<?> clazz = Class.forName("zzz");
        Constructor<?> constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        constructor.newInstance();
    }
}
class zzz{
    private zzz(){
        System.out.println("this is zzz");
    }
    private zzz(String name){
        System.out.println("this is "+name);
    }
    private zzz(int age,String name){
        System.out.println("this is "+age+":"+name);
    }
}

  

 

   如果我們想獲取有參構造方法怎麼做?

  一樣使用getDeclaredConstructor();

  

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

public class Reflection {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        Class<?> clazz = Class.forName("zzz");
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        constructor.newInstance("test");
    }
}
class zzz{
    private zzz(){
        System.out.println("this is zzz");
    }
    private zzz(String name){
        System.out.println("this is "+name);
    }
    private zzz(int age,String name){
        System.out.println("this is "+age+":"+name);
    }
}

  

 

 

除了使用getDeclaredConstructor

還可以使用getDeclaredConstructors
  
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Reflection {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        Class<?> clazz = Class.forName("zzz");
//        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
//        constructor.setAccessible(true);
//        constructor.newInstance("test");
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        Constructor constructor = constructors[0];
        constructor.setAccessible(true);
//      輸出內容
        System.out.println(constructor);
        constructor.newInstance();
    }
}
class zzz{
    private zzz(){
        System.out.println("this is zzz");
    }
    private zzz(String name){
        System.out.println("this is "+name);
    }
    private zzz(int age,String name){
        System.out.println("this is "+age+":"+name);
    }
}

  如果想獲取有參構造方法:

getDeclaredConstructors
帶s說明獲取所有構造方法,[0]代表第一位:
  

 

   有參構造方法在第1位置,那麼修改demo:

  

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

public class Reflection {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        Class<?> clazz = Class.forName("zzz");
//        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
//        constructor.setAccessible(true);
//        constructor.newInstance("test");
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        Constructor constructor = constructors[1];
        constructor.setAccessible(true);
//      輸出內容
        System.out.println(constructor);
        constructor.newInstance("test");
    }
}
class zzz{
    private zzz(){
        System.out.println("this is zzz");
    }
    private zzz(String name){
        System.out.println("this is "+name);
    }
    private zzz(int age,String name){
        System.out.println("this is "+age+":"+name);
    }
}

  

 

 

獲取私有構造方法,私有字段,私有方法:

  

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class reflection2 {
    public static <Feild> void main(String[] args) throws Exception {
        //獲取類
        Class clazz=Class.forName("test");
        //獲取私有方法
        Constructor c = clazz.getDeclaredConstructor();
        c.setAccessible(true);
        //獲取私有方法
        Method method = clazz.getDeclaredMethod("test", String.class, String.class);
        method.setAccessible(true);
        method.invoke(c.newInstance(),"aaa","bbb");
        //獲取私有字段
        Field field = clazz.getDeclaredField("age");
        field.setAccessible(true);
        System.out.println(field.get(c.newInstance()));
    }
}

class test{
    private test(){
        System.out.println("test");
    }
    private int age=222;
    private void test(String name1,String name2){
        System.out.println(name1+":"+name2);
    }
}

  

 

 

即使構造方法,字段,方法是public,也是受用的。

反射調用java.lang.Runtime方法:
Runtime類的構造方法是私有的,所以我們代碼如下:
  
public class reflection3 {
    public static void main(String[] args) throws Exception {
        //Class clazz=Class.forName("java.lang.Runtime");
       // clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),"open /Users/maniac/aaaa.txt");
        Class clazz = Class.forName("java.lang.Runtime");
        //獲取構造方法,包含public,private,protect
        Constructor c = clazz.getDeclaredConstructor();
        c.setAccessible(true);
        clazz.getMethod("exec", String.class).invoke(c.newInstance(),"open /Users/maniac/aaaa.txt");
    }
}

  啓動成功:

  

 

 

  java.lang.Runtime反射調用2:

因爲java.lang.Runtime執行命令是:java.lang.Runtime.getRuntime().exec()
  

 

 

所以直接調用:

getRuntime()和exec()方法都是公開方法,那麼可以這樣:
  
public class reflection4 {
    public static void main(String[] args) throws Exception {
       // java.lang.Runtime.getRuntime().exec();
        Class clazz=Class.forName("java.lang.Runtime");
        clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),"open /Users/maniac/aaaa.txt");
    }
}

 

  優先獲取最後的方法,然後往前移動。

 

 

流程:java.lang.Runtime.getRuntime().exec(command)->exec()->exec()->getRuntime()->java.lang.Runtime->command

修改私有屬性和方法裏面的屬性:

  

import jdk.nashorn.internal.objects.NativeDebug;

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

public class Reflection {


    private static java.lang.Object Object;

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException, NoSuchFieldException {
        Class<?> clazz = Class.forName("zzz");
        Class.forName("java.lang.Runtime");
//        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
//        constructor.setAccessible(true);
//        constructor.newInstance("test");
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        Constructor constructor = constructors[1];
        constructor.setAccessible(true);
//      輸出內容
        System.out.println(constructor);
//        constructor.newInstance("test");
//        Method xxx = clazz.getMethod("xxx");
//        System.out.println(xxx);
        //實例化
        Object o=constructor.newInstance("test");
        Field field = clazz.getDeclaredField("name");
        field.setAccessible(true);
        field.set(o,"hello");
        Object xx=field.get(o);
        //修改變量
        System.out.println(xx);
//        System.out.println(field.get(constructor.newInstance("test")));
//         clazz.getMethod("xxx").invoke(constructor.newInstance("test"));
//        clazz.getDeclaredField("name").setAccessible(true);
        Method method = clazz.getDeclaredMethod("xxx");
        method.setAccessible(true);
        //修改方法
        method.invoke(o);



    }
}
class zzz{
    private zzz(){
        System.out.println("this is zzz");
    }
    private zzz(String name){
        System.out.println("this is "+name);
    }
    private zzz(int age,String name){
        System.out.println("this is "+age+":"+name);
    }
    public int age=123;
    private String name="jack";
    public void xxx(){
        System.out.println(name);
    }
}

  

 

 

總結:getMethod:是獲取方法

invoke是執行方法,裏面放的是實例化類
newInstance()是對類的實例化
  
獲取字段返回類型:
  
Field i = demo.getDeclaredField("i");
i.setAccessible(true);
int modifiers = i.getModifiers();

  

 

 

  返回類型有這些:

  

PUBLIC: 1
PRIVATE: 2
PROTECTED: 4
STATIC: 8
FINAL: 16
SYNCHRONIZED: 32
VOLATILE: 64
TRANSIENT: 128
NATIVE: 256
INTERFACE: 512
ABSTRACT: 1024
STRICT: 2048

  去final修飾符修改字段:

  

 

   測試demo:

反射修改number爲13:
  
Class<?> aClass = Class.forName("com.reflection.demo");
Field number = aClass.getDeclaredField("number");
number.setAccessible(true);
Field modifiers = number.getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(number,number.getModifiers()&~Modifier.FINAL);
number.setInt(null,13);
System.out.println(number.get(null));

  

 

 

  反射調用內部類:

  

 

 

//反射調用內部類
@Test
public void test4() throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
    Class c = Class.forName("com.test.BasicTest.refInnerClass");
    Constructor declaredConstructor1 = c.getDeclaredConstructor();
    declaredConstructor1.setAccessible(true);
    //通過方法名獲取方法
    Method method = c.getDeclaredMethod("print");
    //調用外部類方法
    method.invoke(c.newInstance());
    //內部類需要使用$分隔
    Class c2 = Class.forName("com.test.BasicTest.refInnerClass$InnerClass");
    Method method2 = c2.getDeclaredMethod("print2");
    Constructor declaredConstructor = c2.getDeclaredConstructor(c);
    declaredConstructor.setAccessible(true);
    method2.setAccessible(true);
    //獲取方法
    method2.invoke(declaredConstructor.newInstance(c.newInstance()));
    //修改isTrue爲true
    Field isTrue = c2.getDeclaredField("isTrue");
    isTrue.setAccessible(true);
    Field modifiers = isTrue.getClass().getDeclaredField("modifiers");
    modifiers.setAccessible(true);
    //去除final修飾符
    modifiers.setInt(isTrue,isTrue.getModifiers()&~Modifier.FINAL);
    isTrue.setBoolean(null,true);
    System.out.println(isTrue.get(null));
    //調用私有方法
    Method test2 = c2.getDeclaredMethod("test2");
    test2.setAccessible(true);
    test2.invoke(declaredConstructor.newInstance(declaredConstructor1.newInstance()));
}

  

 

 

  for循環反射調用內部類方法和字段:

//反射內部類批量調用方法,字段名字
@Test
public void test5() throws ClassNotFoundException {
    com.test.BasicTest.refInnerClass refInnerClass = new refInnerClass();
    Class<?> aClass = Class.forName("com.test.BasicTest.refInnerClass");
    //獲取所有類
    Class<?>[] declaredClasses = refInnerClass.class.getDeclaredClasses();
    Arrays.stream(declaredClasses).forEach(clazz -> {
        Arrays.stream(clazz.getDeclaredMethods()).forEach(method -> {
            Arrays.stream(clazz.getDeclaredFields()).forEach(field -> {
                field.setAccessible(true);
                method.setAccessible(true);
                try {

                    // 獲取內部類的構造方法,內部類的構造只能通過外部類來獲取
                    Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(aClass);
                    declaredConstructor.setAccessible(true);
                    // 由外部類對象來反射獲取內部類的對象
                    Object o = declaredConstructor.newInstance(aClass.newInstance());
                    method.invoke(o);
                    Field modifiers = field.getClass().getDeclaredField("modifiers");
                    modifiers.setAccessible(true);
                    modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
                    Object o1 = field.get(o);
                    System.out.println(o1);
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchFieldException e) {
                    e.printStackTrace();
                }
            });
        });
    });
}

 

  for循環反射調用類的方法和字段:

    

 @Test
    //反射批量調用方法,名字
    public void test6() throws ClassNotFoundException {
        Class<?> aClass = Class.forName("com.test.BasicTest.reflectionDemo");
        Arrays.stream(aClass.getDeclaredMethods()).forEach(method -> {
            Arrays.stream(aClass.getDeclaredFields()).forEach(field -> {
                method.setAccessible(true);
                field.setAccessible(true);
                try {
                Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();;
                declaredConstructor.setAccessible(true);
                method.invoke(declaredConstructor.newInstance());
                Object o = field.get(null);
                System.out.println(o);
                } catch (IllegalAccessException | InvocationTargetException |NoSuchMethodException|InstantiationException e) {
                    e.printStackTrace();
                }
            });
        });
    }

    無關緊要的一些反射加載類縮寫:

    

一個數組 [Ljava.lang.String;
二維數組 [[Ljava.lang.String;
三維數組 [[[Ljava.lang.String;

  

float[].class=[F  
double[].class=[D  
long[].class=[J  
int[].class=[I    
short[].class=[S   
char[].class=[C  
byte[].class=[B   
Boolean[].class=[Ljava.lang.Boolean;   
Integer[].class=[Ljava.lang.Integer;   
Object[].class=[Ljava.lang.Object;

  一個[爲一維數組,2個[爲2維,依次遞增

  後續如果還有反射知識點再補充

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章