反射的具体学习与应用,超详细篇

在计算机学科中,反射是指计算机程序在运行时可以访问、检测和修改它本身状态或行为的一种能力。通过Java的反射机制,程序员可以更深入地控制程序的运行过程,如在程序运行时对用户输入的信息进行验证,还可以逆向控制程序的执行过程。理解反射机制是学习Spring框架的基础。

一、反射简介

(1)Java的反射机制是一种动态获取信息以及动态调用对象的方法的功能。

(2)具体来说,在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。

(3)通过Java反射机制,就可以在程序中访问已经装载到JVM中的Java对象的各种描述,能够访问、检测和修改描述Java对象本身信息。

(4)Java在java.lang.reflect包中提供了对该功能的支持。

二、反射与Class类

(1)反射与Class类息息相关。Class对象封装了它所代表的类的描述信息,通过调用Class对象的各种方法,就可以获取到Class对象所代表的类的主要描述信息。

(2)获取目标类的Class对象,有以下3种方法可以实现:

  1. 使用Object类的getClass()方法

  2. 使用Class类的forName(String url)方法,用目标类的完整路径作为参数

  3. 使用目标类的class属性

在com.cxyzxc.reflect包中定义Person类

package com.cxyzxc.www.entity;
​
public class Person {
​
    //公共属性
    public String name;
    //私有属性
    private int age;
​
    //无参构造
    public Person() {
        this.name = "张三";
        this.age = 18;
    }
​
    //有参构造
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //私有有参构造
    private Person(String name) {
        this.name = name;
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
​
    //无参方法
    public void eat(){
        System.out.println("今天吃了1顿大餐");
    }
​
    //带参方法
    public void eat(int num){
        System.out.println("今天吃了"+num+"顿大餐");
    }
​
    //私有方法
    private void sleep(){
        System.out.println("非常舒服的睡了一觉");
​
    }
}
​

获取Class类对象

package com.cxyzxc.www.reflect;
​
import com.cxyzxc.www.entity.Person;
​
public class Demo01GetClass {
​
    public static void main(String[] args) throws ClassNotFoundException {
        //获取Class对象
        //方法一:使用Class.forName()方法
        Class personClass1 =Class.forName("com.cxyzxc.www.entity.Person");
​
        //方法二:使用类的class属性
        Class personClass2 = Person.class;
​
        //方法三:使用Object类中的getClass()方法
        Person person = new Person();
        Class personClass3 = person.getClass();
​
        //使用Class.forName()方法和使用类的class属性获取的Class对象是同一个对象
        System.out.println("personClass1和personClass2是同一个对象:"+(personClass1==personClass2));//true
        //使用类的class属性和使用Object类中的getClass()方法获取的Class对象是同一个对象
        System.out.println("personClass1和personClass2是同一个对象:"+(personClass2==personClass3));//true
​
    }
}

(3)Class对象常用方法如下表所示:

方法功能描述
Package getPackage()获得类所在的包路径
String getName()获得类(或接口、数组等)的名称
Class getSuperclass()获得该类的父类的Class对象
Class getInterfaces()获得该类实现的所有接口
Constructor[] getConstructors()获得该类的public修饰的构造方法,按声明顺序返回
Constructor getConstructor(Class<?>...ParameterType)获得该类的public修饰的特定参数列表的构造方法
Constructor[] getDeclaredConstructors()获得该类的所有构造方法
Constructor getDeclaredConstructors(Class<?>...ParameterType)获得该类的特定参数列表的构造方法
Method[] getMethods()获得该类的所有public修饰的方法
Method getMethod(String name,Class<?>...ParameterType)获得该类的public修饰的特定参数列表的方法
Method[] getDeclaredMethods()获得该类的所有方法,包含private修饰的方法,按声明顺序返回
Method[] getDeclaredMethods(String name,Class<?>...ParameterType)获得该类的特定参数列表的方法,包括private修饰的方法
Field[] getFields()获得该类的所有public修饰的成员变量
Field getField(String name)获得该类的public修饰的特定名称的成员变量
Field[] getDeclaredFields()获得该类的所有成员变量,包括private修饰的成员变量,按声明顺序返回
Field getDeclaredField(String name)获得特定名称的成员变量

三、反射访问构造方法

使用Class对象的如下方法,将返回Constructor类型对象或数组,每个Constructor代表一个构造方法。

方法功能描述
Constructor getConstructor()返回Constructor,匹配public修饰的不带参的构造方法
Constructor[] getConstructors()返回Constructor数组,匹配public修饰的所有构造方法
Constructor getConstructor(Class<?>...ParameterType)返回Constructor,匹配和参数列表相同的构造方法
Constructor[] getConstructors(Class<?>...ParameterType)返回Constructor数组,匹配和参数列表相同的构造方法
Constructor getDeclaredConstructor()返回Constructor,匹配包括private修饰的不带参的构造方法
Constructor[] getDeclaredConstructors()返回Constructor数组,匹配包括private修饰的构造方法
Constructor getDeclaredConstructor(Class<?>...parameterTypes)返回Constructor,匹配包括private修饰的和参数列表相同的构造方法
Constructor[] getDeclaredConstructors(Class<?>...parameterTypes)返回Constructor数组,匹配包括private修饰的和与参数列表想用的构造方法

其中,带有Class<?>...parameterType字样的方法代表构造方法的参数列表,实际运用时需要指定具体的类型。

Constructor类常用方法如下所示:

方法功能描述
boolean isVarargs()查看该构造方法是否带有可变数量的参数
Class[] getParameterTypes()获得该构造方法的各个参数的类型
Class[] getExceptionTypes()获得该构造方法可能抛出的异常类型
Object newInstance(Object...initargs)通过该构造方法利用指定参数创建一个该类的对象,如果未设置参数,则表示采用默认无参数的构造方法
void setAccessible(boolean flag)如果该构造方法的权限为private,默认不允许通过反射利用newInstance(Object...iniargs)方法创建对象。如果先执行该方法,并将入口参数设为true,则允许创建
int getModifiers()返回构造方法所用修饰符的整数

使用反射访问Person类的构造方法

package com.cxyzxc.www.reflect;
​
import com.cxyzxc.www.entity.Person;
​
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
​
public class Demo02GetConstructors {
​
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取Class对象
        Class<Person> personClass1 = Person.class;
​
        System.out.println("--------------输出所有public修饰的构造方法--------------");
​
        //获得所有public修饰的构造方法
        Constructor[] constructors1 = personClass1.getConstructors();
        //遍历所有的构造方法
        for(Constructor constructor:constructors1){
            //输出构造方法对象
            System.out.println("构造方法:"+constructor);
            //获取构造方法的参数列表
            Class[] types = constructor.getParameterTypes();
            //遍历当前构造方法的参数列表
            for(int i = 0 ;i<types.length;i++){
                System.out.println("\t参数"+(i+1)+"类型:"+types[i]);
            }
        }
​
        System.out.println("--------------输出所有构造方法--------------");
​
        //获取所有构造方法
        Constructor[] constructors2 =personClass1.getDeclaredConstructors();
        //遍历输出所有Construct对象
        for (Constructor constructor:constructors2){
            //输出构造方法对象
            System.out.println("构造方法:"+constructor);
            //输出构造方法修饰符
            System.out.println("\t构造方法修饰符:"+(constructor.getModifiers()==1?"public":"private"));
            //获取构造方法的参数列表
            Class[] types = constructor.getParameterTypes();
            //遍历当前构造方法的参数列表
            for(int i = 0 ;i<types.length;i++){
                System.out.println("\t参数"+(i+1)+"类型:"+types[i]);
            }
​
        }
​
        System.out.println("--------------访问特定的构造方法--------------");
        System.out.println("-------无参构造方法-------");
        //获取无参构造方法
        Constructor constructor1 =personClass1.getConstructor();
        //通过无参构造方法创建Person对象
        Person person1=(Person) constructor1.newInstance();
        System.out.println(person1);
​
        System.out.println("-------有参构造方法-------");
        //获取有参构造方法
        Constructor constructor2 =personClass1.getConstructor(String.class,int.class);
        //通过有参构造方法创建对象
        Person person2=(Person)constructor2.newInstance("王五",25);
        System.out.println(person2);
​
    }
}

四、反射访问成员变量

使用Class对象的如下方法,将返回Field型对象或数组。Field对象代表一个成员变量,利用Field对象可以访问和操纵相应的成员变量。

方法功能描述
getFields()获得所有的public修饰的成员变量
getFields(String name)获得指定名称的public修饰的成员变量
getDeclareFields()获得所有的成员变量,包括private修饰的成员变量
getDeclaredField(String name)获得指定名称的成员变量,包括private修饰的成员变量

Field类的常用方法

方法功能描述
String getName()返回该成员变量的名称
Class getType()返回表示该成员变量的类型的Class对象
Object get(Object obj)返回指定对象中成员变量的值
void set(Object obj,Object value)设置对象obj中成员变量的值为value
int getInt(Object obj)返回指定对象obj中类型为int的成员变量的值
void setInt(Object obj,int value)设置对象obj中类型为int的成员变量的值为value
float getFloat(Object obj)返回指定对象obj中类型为float的成员变量的值
setFloat(Object obj,float value)设置对象obj中类型为float的成员变量的值为value
boolean getBoolean(Object obj)返回指定对象obj中类型为boolean的成员变量的值
setBoolean(Object obj,boolean value)设置对象obj中类型为boolean的成员变量的值为value
getAccessible(boolean flag)设置是否允许直接访问private等私有权限的成员变量
getModifiers()返回成员变量所用修饰符的整数

反射访问Person送类的成员变量

package com.cxyzxc.www.reflect;
​
import com.cxyzxc.www.entity.Person;
​
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
​
public class Demo03GetFields {
​
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //获取Class对象
        Class personClass1 = Class.forName("com.cxyzxc.www.entity.Person");
        //获取有参构造方法
        Constructor constructor1 =personClass1.getConstructor(String.class,int.class);
        //通过有参构造方法创建对象
        Person person1= (Person) constructor1.newInstance("张三",28);
​
        System.out.println("-------------------遍历所有public修饰的属性-------------------");
​
        //获取所有public修饰的成员变量
        Field[] publicFields1 =personClass1.getFields();
        //遍历所有public修饰的属性
        for (Field pubField:publicFields1) {
            System.out.println("成员变量名称:"+pubField.getName());
            System.out.println("成员变量类型:"+pubField.getType());
            //获取成员变量的值
            if(pubField.getType().equals(String.class)){
                System.out.println("成员变量值:"+pubField.get(person1));
            }else if(pubField.getType().equals(int.class)){
                System.out.println("成员变量值:"+pubField.getInt(person1));
            }
        }
​
        System.out.println("-------------------遍历所有属性-------------------");
        Field[] fields = personClass1.getDeclaredFields();
        for (Field field:fields){
            System.out.println("成员变量名称:"+field.getName());
            System.out.println("成员变量类型:"+field.getType());
            System.out.println("成员变量修饰:"+(field.getModifiers()==1?"public":"private"));
            //获取成员变量值
            if(field.getType().equals(String.class)){
                System.out.println("成员变量值:"+field.get(person1));
            }else if(field.getType().equals(int.class)){
                //如果是私有的成员变量
                if(field.getModifiers()== Modifier.PRIVATE){
                    //设置可以访问。不然会抛出IllegalAccess Exception
                    field.setAccessible(true);
                }
                System.out.println("成员变量值:"+field.getInt(person1));
            }
        }
​
​
        System.out.println("-------------------访问特定的成员变量-------------------");
        //获取姓名属性
        Field field1 = personClass1.getField("name");
        //修改姓名属性值
        field1.set(person1,"李二狗");
        System.out.println(person1);
​
        //反射获取私有成员变量,会抛出异常
//        Field field2 =personClass1.getFields("age");
//        System.out.println(field2);
​
        //暴力获取私有字段
        Field field2 = personClass1.getDeclaredField("age");
        field2.setAccessible(true);
        field2.set(person1,30);
        System.out.println(person1);
    }
}

五、反射访问成员方法

使用Class对象的如下方法,将返回Method型对象或数组,Method对象代表一个方法。

方法功能描述
getMethods()获得所有public修饰的方法,包括父类的方法
getMethod(String name,Class<?>...parametertTypes)获得public修饰的特定名称和参数列表的方法
getDeclaredMethods()获得所有方法,包括private修饰的方法,但不包括父类的方法
getDeclaredMethod(String name,Class<?>..parameterTypes)获得特定名称和参数列表的方法,包括private修饰的方法

Method类的常用方法

方法功能描述
String getName()返回该方法的名称
Class[] getParameterTypes()返回该方法的各个参数的类型
Class getReturnType()返回该方法的返回值的类型
Class[] getExceptionTypes()返回该方法可能抛出的异常
Object invoke(Object obj,Object...args)用参数args执行指定对象obj中的该方法
boolean isVarArgs()查看该成员方法是否带有可变数量的参数
int getModifiers()获得可以解析出该方法所采用修饰符的整数

反射访问Person类的成员方法

package com.cxyzxc.www.reflect;
​
import com.cxyzxc.www.entity.Person;
​
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
​
public class Demo04GetMethods {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
​
        //获取Class对象
        Class PersonClass1 = Person.class;
        Person person1 = new Person();
​
        System.out.println("-----------------------获取所有public修饰的方法(包括Object类中的方法)-----------------------");
        Method[] methods1 = PersonClass1.getMethods();
        //遍历输出所有的方法
        for(Method method : methods1){
            //输出方法名称
            System.out.println("方法名:"+method.getName());
        }
​
        System.out.println("-----------------------获取所有方法(不包括Object类中的方法)-----------------------");
        Method[] methods2 = PersonClass1.getDeclaredMethods();
        //遍历输出所有的方法
        for(Method method : methods2){
            //输出方法名称
            System.out.println("方法名:"+method.getName());
        }
​
        System.out.println("-----------------------获取指定名称的方法并使用(无参方法)-----------------------");
        Method m1 = PersonClass1.getMethod("eat");
        //调用方法
        m1.invoke(person1);//等价于person.eat()
​
        System.out.println("-----------------------获取指定名称的方法并使用(有参方法)-----------------------");
        Method m2 = PersonClass1.getMethod("eat",int.class);
        //调用方法
        m2.invoke(person1,5);//等价于person.eat(5)
​
        System.out.println("-----------------------获取指定名称的私有方法并使用(私有方法)-----------------------");
        Method m3 = PersonClass1.getDeclaredMethod("sleep");
        //因为方法是私有方法,要设置访问权限才能访问
        m3.setAccessible(true);
        //调用方法
        m3.invoke(person1);
​
        System.out.println("-----------------------判断方法的返回值类型-----------------------");
        Method m4 = PersonClass1.getMethod("getAge");
        System.out.println("方法返回值类型:"+m4.getReturnType());
​
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值