Java反射基础

Java官方对于反射的解释是这样的:

反射允许对封装类的字段、方法和构造函数的信息进行编程访问

也就是说Java的反射机制能够获取类的所有信息,包括任何访问权限的字段,方法和构造器,并且获取之后还能够对齐进行调用和访问。
下面将分别介绍Java反射机制获取类——Class,方法——Method,字段——Field,构造器——Constructor。

Class

用于描述字节码文件的。我们知道java文件被编译后会形成class文件,java文件中的每一个类都会形成一个class文件,而Class类就是用于描述class文件的。这个类有一些方法我们需要了解。

获取Class

我们有三种方式可以获取去某个类的字节码文件的对象。

  1. 利用Class类中的静态方法forName获取
    方法名作用
    static Class<?> forName(String className)根据类的全类名获取它的类信息
  2. 通过类名.class获取
  3. 通过对象.getClass()获取
public class Demo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //1. 利用Class类中的静态方法forName获取
        Class clazz1 = Class.forName("java.util.HashMap");

        //2. 通过类名.class获取
        Class clazz2 = HashSet.class;

        //3. 通过对象.getClass()获取
        ArrayList<Integer> list = new ArrayList<>();
        Class clazz3 = list.getClass();

        System.out.println(clazz1);
        System.out.println(clazz2);
        System.out.println(clazz3);
    }
}

运行结果如下:
在这里插入图片描述
获取某个类的Class对象之后进而可以利用它去获取类的构造器、方法、字段等信息。

获取Constructor

获取一个类的Class对象后我们可以利用这个Class对象的下面方法获取此类的各种构造器。

方法名作用
Constructor<?>[] getConstructors()获取本类全部的public修饰的构造器
Constructor getConstructor(Class<?>… parameterTypes)根据类型参数获取指定的public构造器
Constructor<?>[] getDeclaredConstructors()获取本类的任何构造器
Constructor getDeclaredConstructor(类<?>… parameterTypes)根据类型参数获取任何指定的构造器

这里我们使用两个方法来演示一下用法,另外两个同理。

public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
    	//获取指定类的Class对象
        Class clazz = Class.forName("java.util.HashMap");
		
		//利用Class对象获取构造器
        Constructor constructor = clazz.getDeclaredConstructor(int.class);
        Constructor[] constructors = clazz.getDeclaredConstructors();

		//输出构造器对象
        System.out.println("获取指定的任何构造器:" + constructor);

        for(Constructor c : constructors){
            System.out.println("获取所有构造器: " + c);
        }
    }
}

运行结果
在这里插入图片描述
获取了构造器对象之后,构造器对象可以干很多事,比如用它实例化对象,获取它的名字等
在这里插入图片描述
下面演示一下使用获取到的构造器对象实例化一个对象。

Class clazz = Class.forName("java.util.HashMap");
Constructor constructor = clazz.getDeclaredConstructor(int.class);

//利用获取到的构造器实例化对象
HashMap<String, String> map = (HashMap<String, String>) constructor.newInstance(12);
map.put("及时雨呼保义孝义黑三郎", "宋江");
map.put("玉麒麟", "卢俊义");
System.out.println(map);

在这里插入图片描述

获取Field

套路类似,先获取Class对象,再根据Class对象获取对象的字段。

方法名作用
Field getField(String name)根据字段名获取指定public修饰的字段
Field[] getFields()获取此类的所有本类的public修饰的字段
Field getDeclaredField(String name)根据字段名获取任何指定的字段
Field[] getDeclaredFields()获取所有本类的字段

这里我们仍然用两个方法演示,其他的用法同理。

//获取Class对象
Class clazz = Class.forName("java.lang.String");

//获取字段
Field[] fields = clazz.getDeclaredFields();
Field field = clazz.getDeclaredField("value");

//输出字段
System.out.println("获取指定的任何字段: " + field);
for(Field f : fields){
    System.out.println("获取所有的字段: " + f);
}

在这里插入图片描述
我们获取字段之后可以获取、修改指定对象这个字段的值。但是如果这个字段在当前类里访问权限不够,需要使用field.setAccessible(true);暂时设置该字段可以访问。

 Class clazz = Class.forName("java.lang.String");

 Field field = clazz.getDeclaredField("value");

 String str = "reflect";
 
 //暂时取消此字段的权限校验
 field.setAccessible(true);
//获取str对象的value属性并输出
 char[] value = (char[]) field.get(str);
 System.out.println(value);

//修改str的value属性
 field.set(str, new char[]{'h', 'e', 'l', 'l', 'o'});
//再次获取str的value属性并输出
 value = (char[]) field.get(str);
 System.out.println(value);

输出结果
在这里插入图片描述

获取Method

方法仍然是跟前面套路类似,但是也有些不同,下面会做出讲解。

方法名作用
Method getMethod(String name, Class<?>… parameterTypes)根据方法的名字和形参列表获取指定public修饰的方法
Method[] getMethods()获取所有包括父类的public修饰的方法
Method getDeclaredMethod(String name, Class<?>… parameterTypes)根据方法名和形参列表获取任何指定的方法
Method[] getDeclaredMethods()获取所有本类的方法

注意getMethods方法能获取父类的方法,这与前面的不同,前面的都是只能获取本类中的信息。

定义一个Student类,其中有四种访问权限的方法
在这里插入图片描述

下面演示对Student类中方法的获取

//获取Class对象
Class clazz = Class.forName("Student");

//用三种方式分别获取Method
Method method = clazz.getDeclaredMethod("sleep", int.class);
Method[] methods1 = clazz.getDeclaredMethods();
Method[] methods2 = clazz.getMethods();

//分别输出method
System.out.println("获取指定的方法:" + method);
for(Method m : methods1){
    System.out.println("获取本类中所有的方法" + m);
}

for(Method m : methods2){
    System.out.println("获取父类和本类中所有的方法" + m);
}

输出结果:在这里插入图片描述
在这里插入图片描述
我们获取到方法后可以利用Method的invoke方法执行指定对象的这个方法,参数为指定的对象和需要传入的参数。如果权限不允许那就利用setAccessible(true)暂时取消权限校验

 Class clazz = Class.forName("Student");

 Method method = clazz.getDeclaredMethod("sleep", int.class);

 Student s = new Student(18, "小明");
 method.setAccessible(true);
 method.invoke(s, 22);

执行结果:
在这里插入图片描述

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值