java基础之--反射详解

1. 反射的基本概念

反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的方法,属性,构造方法等成员

在这里插入图片描述

1.1 使用反射机制解剖类的前提

必须先要获取到该类的字节码文件对象,即Class类型对象,关于Class描述字节码文件如下图所示

  • java中使用Class类表示某个class文件
  • 任何一个Class文件都是Class这个类的一个实例对象

在这里插入图片描述

1.2 获取Class对象的三种方式

package Reflect;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-05-21 15:53
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception{
        // 通过类名 .class 获取
        Class studentClass = Student.class;
        System.out.println(studentClass);

        // 通过Object类的getClass()方法获取
        Student student = new Student();
        Class c = student.getClass();
        System.out.println(c);

        // 通过class.forName("全限定类名")方法获取
        Class c1 = Class.forName("java.lang.String");
        System.out.println(c1);
    }
}

1.3 获取Class对象的信息

Class对象相关方法

String getSimpleName(); 获得简单类名,只是类名,没有包 
String getName(); 获取完整类名,包含包名+类名 
T newInstance() ;创建此 Class 对象所表示的类的一个新实例。要求:类必须有public的无参数构造方法
package Reflect;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-05-21 15:53
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception{
        // 通过class.forName("全限定类名")方法获取
        Class c = Class.forName("java.lang.String");
        // 获取简单类名
        String simpleName = c.getSimpleName();
        System.out.println("simpleName = "+simpleName);

        // 获取完整类名
        String name = c.getName();
        System.out.println("name = "+name);

        // 创建字符串对象
        String str  = (String) c.newInstance();
        System.out.println(str);
    }
}

1.4 获取Class对象的Constructor信息

一开始在阐述反射概念的时候,我们说到利用反射可以在程序运行过程中对类进行解剖并操作里面的成员。而一般常操作的成员有构造方法,成员方法,成员变量等等,那么接下来就来看看怎么利用反射来操作这些成员以及操作 这些成员能干什么,先来看看怎么操作构造方法。而要通过反射操作类的构造方法,我们需要先知道一个 Constructor类

在这里插入图片描述

Class类中与Constructor相关方法

1. Constructor getConstructor(Class... parameterTypes)
根据参数类型获取构造方法对象,只能获得public修饰的构造方法
如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常

2. Constructor getDeclaredConstructor(Class... parameterTypes)
根据参数类型获取构造方法对象,包括private修饰的构造方法
如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常

3. Constructor[] getConstructors() 
获取所有的public修饰的构造方法 

4. Constructor[] getDeclaredConstructors() 
获取所有构造方法,包括privat修饰的

5. T newInstance(Object... initargs) 根据指定参数创建对象

6. void setAccessible(true) 暴力反射,设置为可以直接访问私有类型的构造方法。
1.4.1 Student类
package Reflect;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-05-21 15:53
 */
public class Student {
    // 姓名
    private String name;
    // 性别
    public String gender;
    // 年龄
    private int age;

    // 有参构造方法
    public Student(String name, String gender, int age) {
        System.out.println("public 修饰有参构造方法");
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    public Student() {
        System.out.println("public 修饰无参构造方法");
    }

    private Student(String name, String gender) {
        System.out.println("private 修饰构造方法");
        this.name = name;
        this.gender = gender;
    }

    // 普通方法
    public void sleep() {
        System.out.println("睡觉");
    }

    public void sleep(int hour) {
        System.out.println("public修饰‐‐‐sleep‐‐‐睡" + hour + "小时");
    }

    private void eat() {
        System.out.println("private修饰‐‐‐eat方法‐‐‐吃饭");
    }

    // 静态方法
    public static void study() {
        System.out.println("静态方法‐‐‐study方法‐‐‐好好学习Java");
    }

    @Override
    public String toString() {
        return "Student{" + "name='" + name + '\'' + ", gender='" + gender + '\'' + ", age=" + age + '}';
    }

	// get -set 方法省略 ......
}

1.4.2 测试类
package Reflect;

import javax.sound.midi.Soundbank;
import java.lang.reflect.Constructor;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-05-21 15:53
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        test01();
        test02();
        test03();
        test04();

    }

    /*
     * 1. Constructor getConstructor(Class ... parmeterTypes)
     * 根据参数类型获取构造方法对象 , 只能获得public修饰的构造方法
     * 如果不存在对应的构造方法, 则会抛出 java.lang.NoSuchMethodException 异常
     * */
    public static void test01() throws Exception {
        System.out.println("test01----------");
        // 获取Student类的class对象
        Class c = Student.class;
        // 根据参数获取构造方法
        Constructor cons = c.getConstructor(String.class, String.class, int.class);
        // 调用Constructor方法创建学生对象
        Student student = (Student) cons.newInstance("张三丰", "男", 120);
        // 输出stu
        System.out.println(student);
    }


    /**
     * 2. Constructor getDeclaredConstructor(Class... parameterTypes)
     * 根据参数类型获取构造方法对象,包括private修饰的构造方法
     * 如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
     */
    public static void test02() throws Exception {
        System.out.println("test02----------");
        // 获取Student类的class对象
        Class c = Student.class;
        // 根据参数获取private修饰构造方法对象
        Constructor cons = c.getDeclaredConstructor(String.class, String.class);
        // 注意:private的构造方法不能直接调用newInstance创建对象,需要暴力反射才可以
        // 设置取消权限检查(暴力反射)
        cons.setAccessible(true);
        // 调用Constructor方法创建学生对象
        Student stu = (Student) cons.newInstance("林青霞", "女");
        // 输出stu
        System.out.println(stu);
    }

    /**
     * 3. Constructor[] getConstructors()
     * 获取所有的public修饰的构造方法
     */
    public static void test03() throws Exception {
        System.out.println("test03----------");
        // 获取Student类的class对象
        Class c = Student.class;
        // 获取所有的public修饰的构造方法
        Constructor[] cons = c.getConstructors();
        for (Constructor con : cons) {
            System.out.println(con);
        }
    }


    /**
     * 4. Constructor[] getDeclaredConstructors()
     * 获取所有构造方法,包括privat修饰的
     * */
    public static void test04() throws Exception{
        System.out.println("test04----------");
        // 获取Student类的class对象
        Class c = Student.class;
        // 获取所有的构造方法
        Constructor[] cons = c.getDeclaredConstructors();
        for (Constructor con : cons) {
            System.out.println(con);
        }
    }
}

输出结果

在这里插入图片描述

1.5 获取Class对象的Method信息

Method是方法类,类中的每一个方法都是Method的对象,通过Method对象可以调用方法

1. Method getMethod("方法名", 方法的参数类型... 类型) 
根据方法名和参数类型获得一个方法对象,只能是获取public修饰的 

2. Method getDeclaredMethod("方法名", 方法的参数类型... 类型) 
根据方法名和参数类型获得一个方法对象,包括private修饰的 

3. Method[] getMethods() (了解) 
获取所有的public修饰的成员方法,包括父类中

4. Method[] getDeclaredMethods() (了解) 
获取当前类中所有的方法,包含私有的,不包括父类中

5. Object invoke(Object obj, Object... args)
根据参数args调用对象obj的该成员方法 如果obj=null,则表示该方法是静态方法 

6. void setAccessible(boolean flag) 
暴力反射,设置为可以直接调用私有修饰的成员方法
1.5.1 示例代码
package Reflect;

import java.lang.reflect.Method;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-05-21 16:56
 */
public class ReflectMethodDemo {
    public static void main(String[] args) throws Exception {
        // 获得Class对象
        Class c = Student.class;
        // 快速创建一个学生对象
        Student stu = (Student) c.newInstance();
        // 获得public修饰的方法对象
        Method sleep = c.getMethod("sleep", int.class);
        sleep.invoke(stu,8);

        // 获取private修饰的方法对象
        Method eat = c.getDeclaredMethod("eat");
        // 注意:private的成员方法不能直接调用,需要暴力反射才可以
        // 设置取消权限检查(暴力反射)
        eat.setAccessible(true);
        // 调用方法eat
        eat.invoke(stu);

        // 获取静态方法对象
        Method study = c.getDeclaredMethod("study");
        // 调用方法study
        // 注意:调用静态方法时,obj可以为null
        study.invoke(null);


        System.out.println("‐‐‐‐‐‐‐‐获得所有public的方法,不包括private,包括父类的‐‐‐‐‐‐‐‐‐‐");
        // 获得所有public的方法,包括父类的
        Method[] ms = c.getMethods();
        for (Method m : ms) {
            System.out.println(m);
        }

        System.out.println("‐‐‐‐‐‐‐‐获得所有方法,包括private,不包括父类‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐");
        // 获得所有方法,包括private,不包括父
        Method[] dems = c.getDeclaredMethods();
        for (Method dem : dems) {
            System.out.println(dem);
        }
    }
}
1.5.2 结果展示

在这里插入图片描述

1.6 获取Class对象的Field信息(了解)

Field是属性类,类中的每一个属性(成员变量)都是Field的对象,通过Field对象可以给对应的成员变量赋值和取值

  • setXxx方法都是给对象obj的属性设置使用,针对不同的类型选取不同的方法
  • getXxx方法是获取对象obj对应的属性值的,针对不同的类型选取不同的方法
1. Field getDeclaredField(String name)
根据属性名获得属性对象,包括private修饰的 

2. Field getField(String name) 
根据属性名获得属性对象,只能获取public修饰的 

3. Field[] getFields() 
获取所有的public修饰的属性对象,返回数组

4. Field[] getDeclaredFields() 
获取所有的属性对象,包括private修饰的,返回数组

void set(Object obj, Object value)
void setInt(Object obj, int i) 
void setLong(Object obj, long l) 
void setBoolean(Object obj, boolean z) 
void setDouble(Object obj, double d) 
Object get(Object obj) 
int getInt(Object obj) 
long getLong(Object obj) 
boolean getBoolean(Object ob) 
double getDouble(Object obj) 
void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性
Class getType(); 获取属性的类型,返回Class对象
1.6.1 示例代码
package Reflect;

import java.lang.reflect.Field;

/**
 * @Description
 * @auther 宁宁小可爱
 * @create 2020-05-21 17:14
 */
public class ReflectFieldDemo {
    public static void main(String[] args) throws Exception{
        // 获得Class对象
        Class c = Student.class;
        // 快速创建一个学生对象
        Student stu = (Student) c.newInstance();

        // 获得public修饰Field对象
        Field f1 = c.getField("gender");
        // 通过f1对象给对象stu的gender属性赋值
        f1.set(stu,"风清扬");
        // 通过f1对象获取对象stu的gender属性值
        String gender = (String) f1.get(stu);
        System.out.println("性别 :" + gender);

        // 获取private修饰Field对象
        Field age = c.getDeclaredField("age");
        // 注意:private的属性不能直接访问,需要暴力反射才可以
        // 设置取消权限检查(暴力反射)
        age.setAccessible(true);
        // 通过age对象给对象stu的age属性赋值
        age.setInt(stu,30);
        // 通过age对象获取对象stu的age属性值
        int num = age.getInt(stu);
        System.out.println("年龄 : "+ num);

        System.out.println("‐‐‐‐‐‐‐获得所有public修饰的属性‐‐‐‐‐‐‐‐");
        // 获得所有public修饰的属性
        Field[] fields = c.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("‐‐‐‐‐‐‐获得所有的属性,包括private修饰‐‐‐‐‐‐‐‐");
        // 获得所有的属性,包括private修饰
        Field[] dels = c.getDeclaredFields();
        for (Field del : dels) {
            System.out.println(del);
        }
    }
}

1.6.2 结果展示

在这里插入图片描述

1.7 总结

反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的方法,属性,构造方法等成员

我们使用反射的时候 , 都需要先获取类的字节码对象 ,最常用的方式就是 Class.forName("类的全限定名") . 我们可以通过字节码对象就可以获取类的构造器 , 从而创建对象 ,最常用的方式是通过字节码对象获取无参构造器 getConstructor , 就可以调用构造器对象的 newInstance() 方法创建对象 , 当然这种方式简化为:字节码对象直接 调用 newInstance() 方法创建对象 . 也可以通过字节码对象获取指定的方法 , 然后调用方法对象的 invoke(Object obj, Object... args) 来执行此方法. 也可以通过字节码对象获取类中的所有字段 , 从而给字段赋值和获取字段的值 . 有了以上的基础 , 我们就可以通过一个指定全限定名 , 就可以创建该类对象的实例对象 , 执行里面的方法 , 给其字段进行赋值或者获取值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫我三胖哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值