java基础之反射

本文介绍了Java中的反射机制,包括Class类型的概念和获取方法,如何通过Constructor构造方法实例化对象,Method成员方法的获取及执行,以及Field成员变量的访问和赋值。还讨论了暴力反射用于访问私有成员以及解决权限问题的setAccessible方法。

反射

1.万恶之源-Class 类型

1.1 概述

Java 中所有的类都是一个模版
所有的类看作一个整体,这个整体对于 Java 而言是一个【类的类型】 Class 类型
Class 类型对象是对应 Java 类型在内存【方法区】空间内容。

class ClassName {
	Field[] fields; // 成员变量 Field 类型数组,成员变量有多个,有一个,或者没有
	Constructor[] constructors; // 构造方法 Constructor 类型数组,构造方法至少有一个,可能允许多个
	Method[] methods; // 成员方法 Method 类型数组,成员方法可以是一个,多个或者没有
}
1.2 Class 类型对象获取方法
Class<?> Class.forName(String packageAndClassName);	

Class 类提供的静态成员方法,根据用户提供的完整的包名.类名,获取对应数据类型的 Class 对象。

Class<? extends T> 任意类对象.getClass();

Java 中任意一个类对象,都可以通过 getClass 方法获取对应的 Class 类型对象。该方法是 Object 类提供给 Java 中所有类型使用的方法

Class<T> 类名.class;

通过 Java 中任意的类名,获取其属性内容,得到对应的 Class 对象。

1.3 Class 相关案例代码

三种方式创建Class对象同时判断这三个对象是否是同一个

public class Person {
    public static void main(String[] args) throws ClassNotFoundException {

         /*
         1. Class<?> Class.forName(String packageAndClassName);
            最常用,也是【工厂模式】的核心方法。
         */
        Class<?> c1 = Class.forName("com.mjl.reflect.Person");
         /*
         2. Class<? extends T> 任意类对象.getClass();
            常用于类型判断,类型校验
         */
        Person person = new Person();
        Class<? extends Person> c2 = person.getClass();

         /*
         3. Class<T> 类名.class;
            常用于类型约束,主要用于反射【方法操作】,类型转换操作
         */
        Class<Person> c3 = Person.class;

        /*
        以上三个 Class 对象是否为同一个对象???
        无论通过哪一种形式获取的 Class 对象,只要是同一个类型,得到的都是
        同一个 Class 对象,对应的是内存【方法区】的同一个数据空间。
         */
        
        System.out.println(c1 == c2);//true
        System.out.println(c3 == c2);//true
        System.out.println(c1 == c3);//true
    }
}

2.反射操作实例化对象 - Constructor 构造方法类型

2.1 概述
对于 Class 对象,构造方法的名称是【类名】,不具备唯一性。在实际调用构造方法,区分构造方法的不同是通过
【参数列表,参数数据类型,参数个数,参数顺序】来区分!!!
2.2 通过 Class 对象获取对应的 Constructor 构造方法对象
Constructor[] getConstructors();

获取当前 Class 对应数据类型的所有【非私有化】构造方法对象数组

// 核心方法 ★
Constructor getConstructor(Class... parameterTypes);

根据用户指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象,并且是【非私有化】构造方法

Constructor[] getDeclaredConstructors();

【暴力反射】获取当前 Class 对应数据类型的所有构造方法对象数组,包括【私有化构造方法】

Constructor getDeclaredConstructor(Class... parameterTypes);

【暴力反射】根据用户指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象,可以获取私有化构造方法

代码示例:

public class Person {
    //属性
    private int age;
    private String name;
    
    public int test = 10;
	public static int testStatic = 10;

    //构造方法 Constructor
    public Person() {}

    public Person(int age) {
        this.age = age;
    }

    private Person(String name) {
        this.name = name;
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
    
      public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        
        
     //成员方法
    }
    	public void game() {
		System.out.println("大吉大利,腾讯倒闭");
	}
	
	public void game(String name) {
		System.out.println("玩" + name);
	}
	
	private void testPrivate() {
		System.out.println("类内私有化成员方法!!!");
	}
	
	private void testPrivate(String str) {
		System.out.println("吃" + str);
	}
	
	public static void test() {
		System.out.println("静态!!!");
	}
    
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

}


public class ConstructorTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        // 获取指定类型的 Class 对象
        Class<?> cls = Class.forName("com.mjl.reflect.Person");

        // 获取当前 Class 对应数据类型的所有【非私有化】构造方法对象数组
        Constructor<?>[] constructors = cls.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }

        System.out.println();
        
         // 根据用户指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象,并且是【非私有化】构造方法
        Constructor<?> c1 = cls.getConstructor();
        Constructor<?> c2 = cls.getConstructor(int.class);
        Constructor<?> c3 = cls.getConstructor(int.class, String.class);

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
      
        // 【暴力反射】获取当前 Class 对应数据类型的所有构造方法对象数组,包括【私有化构造方法】
        Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

        System.out.println();

      // 【暴力反射】根据用户指定的参数类型,顺序,个数获取对应的 Constructor 构造方法对象,可以获取私有化构造方法
        Constructor<?> c4 = cls.getDeclaredConstructor(String.class);
        System.out.println(c4);
 

    }
}
2.3 Constructor 对象实例化对象操作

使用方法

Object newInstance(Object... parameterValues); // 重点方法 ★

通过 Constructor 构造方法对象调用 newInstance 进行实例化对象操作,当前 newInstance 方法所需参数是构造方法参数列表对应的实际参数,采用的参数形式为 Object… 支持任意类型的不定长参数。可以支持没有参数,一个参数或者多个参数,在方法内部是一个 Object 类型的数组

代码示例:

 Constructor<?> c2 = c1s.getConstructor(int.class, String.class);
        Person person = (Person)c2.newInstance(12,"张三");
        System.out.println(person);

3.反射操作核心 - Method

3.1 概述

Method 成员方法类型,通过 Class 对象获取关注点是【方法名】和【形式参数列表】

3.2 通过 Class 对象获取对应的 Method 成员方法对象
Method[] getMethods();

可以获取 Class 对象对应类型的所有非私有化成员方法对象数组,包括父类继承给子类可以供子类使用的成员方法

// 核心方法 ★
Method getMethod(String methodName, Class... parameterTypes);

根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,只能是非私有化成员方法和父类继承给子类使用的方法。

Method[] getDeclaredMethods();

【暴力反射】可以获取 Class 对象对应类型的所有成员方法对象数组,包括私有化成员方法,但是不包括继承方法父类的成员方法。有且只有子类自身方法

Method getDeclaredMethod(String methodName, Class... parameterTypes);

【暴力反射】根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,包括私有化成员方法,不包括父类继承到子类的方法。仅获取子类自有方法

代码示例:

public class MethodTest {
    public static void main(String[] args)
            throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 获取指定类型的 Class 对象
        Class<?> cls = Class.forName("com.mjl.reflect.Person");
        // 可以获取 Class 对象对应类型的所有非私有化成员方法对象数组,包括父类继承给子类可以供子类使用的成员方法
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        System.out.println();
        /*
         【暴力反射】可以获取 Class 对象对应类型的所有成员方法对象数组,包括私有化成员方法,但是不包括继承方法父类的成员方法。
         有且只有子类自身方法
        */
        Method[] declaredMethods = cls.getDeclaredMethods();

        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }

        System.out.println();
        /*
        根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,
        只能是非私有化成员方法和父类继承给子类使用的方法。
         */
        Method game1 = cls.getMethod("game");
        Method game2 = cls.getMethod("game", String.class);

        System.out.println(game1);
        System.out.println(game2);

        System.out.println();
        /*
        【暴力反射】根据指定的方法名称 (methodName) 和指定的方法参数类型,获取成员方法对象,包括私有化成员方法,
        不包括父类继承到子类的方法。仅获取子类自有方法
         */
        Method m1 = cls.getDeclaredMethod("testPrivate");
        Method m2 = cls.getDeclaredMethod("testPrivate", String.class);
        System.out.println(m1);
        System.out.println(m2);
      

    }
}

4.3 Method 成员方法对象执行对应方法操作

通过 Method 对象使用以下方法,执行对应方法运行目标

Object invoke(Object obj, Object... parameterValues); // 重点方法 ★

第一个参数 obj 执行当前方法的调用者,静态成员方法可以直接对应类实例化对象,或者 null

第二个参数是当前方法所需的实际参数列表,采用 Object 不定长参数形式,不限制任何的参数类型

【重点】

invoke 方法返回值类型为 Object 类型,支持当前目标方法的返回值,如果执行目标方法没有返回值,invoke 最终返回 null

代码示例:

// 实例化对象
Object o = cls.getConstructor().newInstance();

// 非私有化成员方法
game1.invoke(o);
game2.invoke(o, "PUBG");

// 私有化成员方法赋予操作权限之后操作
System.out.println();
m1.setAccessible(true);
m2.setAccessible(true);
m1.invoke(o);
m2.invoke(o, "饺子");

4. 反射操作数据存储和获取 - Field

4.1 概述
针对于类内的成员变量,唯一的标识【成员变量名】
4.2 通过 Class 对象获取对应的 Field 成员变量对象
Field[] getFields();

获取类内所有非私有化成员变量对象数组

Field[] getDeclaredFields(); // 重点方法 ★

【暴力反射】获取类内所有成员变量对象数组,包括私有化成员变量对象

Field getField(String fieldName);

根据指定的成员变量名称,获取对应的非私有化成员变量对象、

Field getDeclaredField(String fieldName); // 重点方法 ★

【暴力反射】根据指定的成员变量名称,获取对应的成员变量对象,包括私有化成员变量

代码示例:

public int test = 10;
private String name;
private int age;


main() {
 Class<?> cls = Class.forName("com.mjl.reflect.Person");
 
 Field f = cls.getField("test");
    
 Field f1 = cls.getDeclaredField("name");

}
4.3 Field 对象操作获取数据和赋值数据

赋值操作方法

void set(Object obj, Object value); // 重点方法 ★

第一个参数 obj 是当前成员变量到底是哪一个类对象。

第二个参数 value 是给予当前成员变量的赋值的数据内容,考虑符合成员变量的数据类型

取值操作

Object get(Object obj); // 重点方法 ★

第一个参数 obj 是当前成员变量到底是哪一个类对象。

返回值类型是当前成员变量存储的数据情况,统一返回 Object 类型,根据所需强转目标数据类型

5.暴力反射权限问题解决

对应方法

void setAccessible(boolean flag); // 重点方法 ★

反射操作中 Constructor, Method ,Field 对象都可以调用该方法解决 私有化反射对象权限操作问题

参数提供为 true 当前私有化构造方法对象有对应的操作权限。

public static void setAccessible(AccessibleObject[] array, boolean flag) // 重点方法 ★

AccessibleObject 类工具方法,所需参数是 AccessibleObject 数组和对应的权限标记,flag 通常为 true。

Field Method Constructor 都是 AccessibleObject 子类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值