java反射笔记,自用 - 飘渺红尘✨
2021-7-17 15:58:0 Author: www.cnblogs.com(查看原文) 阅读量:7 收藏

  以前的学习笔记,自用的反射笔记,比较杂乱无章,甚在内容全

  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维,依次递增

  神坑:java反射数组参数,Runtime.exec 传递new String报错问题:

  反射数组参数参考:https://www.jianshu.com/p/b8873c1ad0ef

  解决:加个(Object),转换为Object

  

  后续如果还有反射知识点再补充


文章来源: https://www.cnblogs.com/piaomiaohongchen/p/15023804.html
如有侵权请联系:admin#unsafe.sh