java-反射

反射

获取class

  • java语言的反射机制可以操作字节码文件
  • 位于java.lang.reflect包下
  • 相关重要类
    • java.lang.Class:代表整个字节码,代表整个类
    • java.lang.Method:代表字节码中的方法字节码
    • java.lang.reflect.Constructor:代表字节码中的构造方法字节码
    • java.lang.reflect.Field:代表字节码中的属性字节码,包括静态变量好实例变量
  • 获取Class的三种方法
  • Class.forName()方法会使java虚拟机加载类文件到方法区,同时类中的静态代码块执行
/*
要操作一个类的字节码,首先要获取这个类的字节码,获取java.lang.Class的三种方式

 */

public class HookTest {
    public static void main(String[] args) {
        //第一种获取Class的方法
        //这样就获取了String的字节码文件
        //参数必须是包括包名的完整类名
        try {
            Class c1 = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //第二种获取Class的方法,x代表String的字节码文件,与上面的c1内存地址相同
        //getClass会获取这个数据类型的类的字节码文件
        //java中的任何一个对象都有getClass方法
        String s = "abc";
        Class x = s.getClass();

        //第三种,java语言中任何一种类型,都有.class属性
        Class ss = String.class;
    }
}

通过反射实例化类

/*
获取class文件的作用:
    通过newInstance方法来实例化对象
    注意如果该类没有无参构造方法,会报异常InstantiationException

 */

public class HookTest {
    public static void main(String[] args) {
        //通过反射机制,获取Class,通过Class实例化队形
        try {
            Class c = Class.forName("TimerTest");
            //newInstance会调用这个类的无参构造方法,完成这个对象的创建
            //注意如果该类没有无参构造方法,会报异常InstantiationException
            Object obj = c.newInstance();
            System.out.println(obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

获取field

/*
获取class文件的作用:
    通过newInstance方法来实例化对象
    注意如果该类没有无参构造方法,会报异常InstantiationException

 */

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class HookTest {
    public static void main(String[] args) {
        try {
            //获取整个类
            Class c =  Class.forName("TimerTest");
            //获取类中所有的Field,这个只能获取public修饰的属性
            Field[] fields = c.getFields();
            //取出第一个这个Field
            Field f = fields[0];
            //获取这个Field的名字
            String fName = f.getName();

            //获取所有的Field,这个方法可以获取不同修饰符的属性
            Field[] fs = c.getDeclaredFields();
            for(Field field:fs){
                //获取修饰符列表,注意单个属性可能有多个修饰符,如public static final String a;
                //注意返回的修饰符的数字代号
                //我们需要通过Modifier这个修饰符类获取修饰符的名称
                int i = field.getModifiers();
                String midifierString = Modifier.toString(i);
                //获取属性的类型,返回的是Class类型
                Class fieldType = field.getType();
                //获取类型的名称,注意这里指的是属性的类型的名字,如:int,float,String等
                String ftName = fieldType.getName();
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

通过反射机制访问java对象的属性

/*
获取class文件的作用:
    通过newInstance方法来实例化对象
    注意如果该类没有无参构造方法,会报异常InstantiationException

 */

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class HookTest {
    public static void main(String[] args) {
        try {
            //获取整个类
            Class c =  Class.forName("TimerTest");
            //实例化这个类
            Object obj = c.newInstance();
            //根据属性名,获取这个属性
            Field a = c.getDeclaredField("a");
            //调用反射机制中属性的set的方法,操作这个类的属性
            //参数:操作的类,要赋的值
            a.set(obj, "world");
            //获取属性的值
            System.out.println(a.get(obj));

            //访问私有属性
            Field b = c.getDeclaredField("b");
            //私有属性需要打包封装
            b.setAccessible(true);
            System.out.println(b.get(obj));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

可变长度参数的Field

  • 语法public static void m(int... args){}
  • 可变长度参数要求的参数个数是0-n个
  • 可变长度参数必须是参数列表的最后一个,且只能有一个

反射Method

  • 获取方法

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class HookTest {
    public static void main(String[] args) throws Exception {
        //获取类
        Class c = Class.forName("TimerTest");
        //获取所有的Method(包括私有的)
        Method[] methods = c.getDeclaredMethods();
        for (Method method:methods){
            //获取方法的修饰符列表
            System.out.println(Modifier.toString(method.getModifiers()));
            //获取方法的返回值类型
            System.out.println(method.getReturnType().getSimpleName());
            //获取方法的名称
            System.out.println(method.getName());
            //获取方法的参数列表
            Class[] parameterTypes = method.getParameterTypes();
            for (Class parameterType:parameterTypes){
                System.out.println(parameterType.getSimpleName());
            }

        }
    }
}

  • 调用方法

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class HookTest {
    public static void main(String[] args) throws Exception {
        //获取类
        Class c = Class.forName("TimerTest");
        //创建对象
        Object obj = c.newInstance();
        //获取Method
        //java通过方法名和参数列表,所有获取方法需要方法名和参数类型
        Method method = c.getDeclaredMethod("eat",String.class,int.class);
        //调用方法,传递对象和参数并使用Object对象获取返回值
        Object retValue = method.invoke(obj,"hello",666);
    }
}

获取父对象

public class HookTest {
    public static void main(String[] args) throws Exception {
        //获取类
        Class c = Class.forName("TimerTest");
        //获取父对象
        Class superc = c.getSuperclass();
        //获取c这个类实现的所有接口
        Class[] interfaces = c.getInterfaces();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值