java基础-chapter17(反射)

本文详细介绍了Java反射机制,包括如何通过Class类获取Class对象,以及如何使用getConstructor、getDeclaredConstructor、getField和getMethod方法获取构造器、字段和方法。此外,还展示了反射在动态加载类、创建对象、调用方法和配置文件应用中的实践示例。
摘要由CSDN通过智能技术生成

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

获取

获取class对象        Class

构造方法        Constructor

字段(成员变量)        Field

成员方法        Method

使用


 

获取class对象的三种方式

1.(源代码阶段)最常用

Class.forName("全类名");

2.(加载阶段)当做参数进行传递

类名.class

3.(运行阶段)已经有了这个类的对象时,才可以使用

对象.getClass();

 示例代码(Student自行创建):

public class reflexDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //第一种方式
        Class c1 = Class.forName("itemFanShe.Student");
        //第二种方式
        Class c2 = Student.class;
        //第三种方式
        Student student = new Student();
        Class c3 = student.getClass();

        //对比
        System.out.println(c1 == c2); //t
        System.out.println(c2 == c3); //t
    }
}

 

利用反射获取构造器

在 java.lang.Class 类中,用于获取构造方法的方法有以下几种:

getConstructor(Class<?>... parameterTypes):

这个方法用于获取指定参数类型的公共构造方法(即声明为 public 的构造方法)。 参数 parameterTypes 是一个可变参数,用于指定构造方法的参数类型。 如果找不到指定参数类型的公共构造方法,会抛出 NoSuchMethodException 异常。

getDeclaredConstructor(Class<?>... parameterTypes):

这个方法用于获取指定参数类型的所有构造方法(包括公共、保护、默认(包)访问以及私有构造方法),但不包括父类的构造方法。 参数 parameterTypes 是一个可变参数,用于指定构造方法的参数类型。 如果找不到指定参数类型的构造方法,会抛出 NoSuchMethodException 异常。 getConstructors():

这个方法用于获取类的所有公共构造方法。 返回一个包含 Constructor 对象的数组,每个 Constructor 对象对应一个公共构造方法。

getDeclaredConstructors():

这个方法用于获取类的所有构造方法(包括公共、保护、默认(包)访问以及私有构造方法),但不包括父类的构造方法。 返回一个包含 Constructor 对象的数组,每个 Constructor 对象对应一个构造方法。

public class reflexDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        /*
        getConstructor(Class<?>... parameterTypes)
        getDeclaredConstructor(Class<?>... parameterTypes)
        getConstructors()
        getDeclaredConstructors()
         */

        //获取class字节码文件对象
        Class c1 = Class.forName("itemFanShe.Student");

        //获取构造方法
        System.out.println("==========getConstructors==========");
        Constructor[] cons1 = c1.getConstructors();
        for (Constructor con : cons1) {
            System.out.println(con);
        }
        System.out.println("==========getDeclaredConstructors==========");
        Constructor[] cons2 = c1.getDeclaredConstructors();
        for (Constructor con : cons2) {
            System.out.println(con);
        }
        System.out.println("==========getDeclaredConstructor==========");
        Constructor con1 = c1.getDeclaredConstructor(); //获取空参构造
        System.out.println(con1);
        Constructor con2 = c1.getDeclaredConstructor(String.class); //获取String类型有参构造器
        System.out.println(con2);
        Constructor con3 = c1.getDeclaredConstructor(int.class); //获取int类型有参构造器
        System.out.println(con3);
        Constructor con4 = c1.getDeclaredConstructor(int.class,String.class); //同时获取两个
        System.out.println(con4);

        int modifiers = con4.getModifiers(); //获取构造方法的权限修饰符 以整数的方式进行返回
        System.out.println(modifiers);

        int parameterCount = con4.getParameterCount(); //获取构造器参数的个数
        System.out.println(parameterCount);

        Class[] parameterTypes = con4.getParameterTypes(); //获取参数的类型
        for (Class parameterType : parameterTypes) {
            System.out.println(parameterType);
        }

        //暴力反射:表示临时取消权限校验
        con2.setAccessible(true);
        Student stu = (Student) con2.newInstance("牛马"); //私有构造器
        System.out.println(stu); //Student{age=0, name='牛马'}

        System.out.println("==========getConstructor==========");
        Constructor con5 = c1.getConstructor(int.class);
        System.out.println(con5);

    }
}

Student类

/**
 * @author hyk~
 */
public class Student {
    private int age;
    public String name;
    private String gender;
    public char sex;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    protected Student() {
    }

    private Student(String name) {
        this.name = name;
    }
    public Student(int age){
        this.age = age;
    }


    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;
    }

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

 

利用反射获取成员变量

  1. getField(String name)

    • 这个方法用于获取指定名称的公共成员变量(即声明为 public 的成员变量)。
    • 参数 name 是要获取的成员变量的名称。
    • 如果找不到指定名称的公共成员变量,会抛出 NoSuchFieldException 异常。
  2. getDeclaredField(String name)

    • 这个方法用于获取指定名称的所有成员变量(包括公共、保护、默认(包)访问以及私有成员变量),但不包括父类的成员变量。
    • 参数 name 是要获取的成员变量的名称。
    • 如果找不到指定名称的成员变量,会抛出 NoSuchFieldException 异常。
  3. getFields()

    • 这个方法用于获取类的所有公共成员变量。
    • 返回一个包含 Field 对象的数组,每个 Field 对象对应一个公共成员变量。
  4. getDeclaredFields()

    • 这个方法用于获取类的所有成员变量(包括公共、保护、默认(包)访问以及私有成员变量),但不包括父类的成员变量。
    • 返回一个包含 Field 对象的数组,每个 Field 对象对应一个成员变量。

 

/**
 * @author hyk~
 */
public class reflexDemo3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        /*
        getField(String name)
        getDeclaredField(String name)
        getFields()
        getDeclaredFields()
         */

        //获取class字节码文件对象
        Class c1 = Class.forName("itemFanShe.Student");

        System.out.println("=============获取公共的成员变量=============");
        Field[] fields = c1.getFields(); //获取所有公共的成员变量
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("=============获取所有成员变量=============");
        Field[] declaredFields = c1.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        System.out.println("=============获取指定名称的公共成员变量=============");
        Field field = c1.getField("name"); //括号里面写变量的名字 无法获取私有
        System.out.println(field);

        System.out.println("=============获取指定名称的所有成员变量=============");
        Field declaredField = c1.getDeclaredField("gender");
        System.out.println(declaredField);

        //获取权限修饰符
        int modifiers = declaredField.getModifiers();
        System.out.println(modifiers); //2

        //获取成员变量名
        String name = declaredField.getName();
        System.out.println(name); //gender

        //获取成员变量的数据类型
        Class<?> type = declaredField.getType();
        System.out.println(type); //class java.lang.String
    }
}

 

利用反射获取成员方法

  1. getMethod(String name, Class<?>... parameterTypes)

    • 这个方法用于获取指定名称和参数类型的公共方法(即声明为 public 的方法)。
    • 参数 name 是要获取的方法的名称,parameterTypes 是一个可变参数,用于指定方法的参数类型。
    • 如果找不到指定名称和参数类型的公共方法,会抛出 NoSuchMethodException 异常。
  2. getDeclaredMethod(String name, Class<?>... parameterTypes)

    • 这个方法用于获取指定名称和参数类型的所有方法(包括公共、保护、默认(包)访问以及私有方法),但不包括父类的方法。
    • 参数 name 是要获取的方法的名称,parameterTypes 是一个可变参数,用于指定方法的参数类型。
    • 如果找不到指定名称和参数类型的方法,会抛出 NoSuchMethodException 异常。
  3. getMethods()

    • 这个方法用于获取类的所有公共方法。
    • 返回一个包含 Method 对象的数组,每个 Method 对象对应一个公共方法。
  4. getDeclaredMethods()

    • 这个方法用于获取类的所有方法(包括公共、保护、默认(包)访问以及私有方法),但不包括父类的方法。
    • 返回一个包含 Method 对象的数组,每个 Method 对象对应一个方法。
public class reflexDemo4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class c1 = Class.forName("itemFanShe.Student");

        System.out.println("获取里面所有的方法对象(包含父类中所有的公共方法)");
        Method[] methods = c1.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        System.out.println("获取里面所有的方法对象(不能获取父类的,但可以获取本类中私有的方法)");
        Method[] declaredMethods = c1.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }

        System.out.println("获取指定的单一方法");
        Method declaredmethod = c1.getDeclaredMethod("eat",String.class);
        System.out.println(declaredmethod);

        //获取方法的修饰符
        int modifiers = declaredmethod.getModifiers();
        System.out.println(modifiers);

        //获取方法的名字
        System.out.println(declaredmethod.getName());

        //获取方法的形参
        Parameter[] parameters = declaredmethod.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        //获取方法抛出的异常
        Class[] exceptionTypes = declaredmethod.getExceptionTypes();
        for (Class exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }

        //方法运行
        Student student = new Student();
        declaredmethod.setAccessible(true); //临时取消权限
        /*
        student:表示方法的调用者
        汉堡包:表示在调用方法的时候传递的实际参数
         */
        String result = (String) declaredmethod.invoke(student,"汉堡包");

        //获取方法的返回值
        System.out.println(result);

    }
}

 

反射的作用

反射是一种强大的编程技术,它使得程序在运行时能够获取和操作类的信息,包括类的属性、方法、构造函数等。反射的主要作用包括以下几个方面:

  1. 动态加载类: 可以通过反射动态加载类,而不需要在编译时知道类的名称。这使得程序可以根据需要在运行时加载和使用类,从而实现更灵活的架构和功能。

  2. 动态创建对象: 反射可以在运行时动态地创建类的对象实例。通过调用类的构造函数,可以在程序运行时根据不同的条件创建不同类型的对象。

  3. 动态调用方法: 反射可以在运行时动态地调用类的方法。程序可以根据需要调用特定名称和参数的方法,而不需要提前在代码中硬编码方法调用。

  4. 动态访问和修改属性: 反射可以在运行时动态地访问和修改类的属性。程序可以通过反射获取类的属性并读取或修改其值,从而实现灵活的属性操作。

  5. 实现通用框架和工具: 反射可以用于实现通用的框架和工具,例如依赖注入、对象映射、动态代理等。通过反射,可以编写通用的代码来处理各种类型的对象和类。

  6. 支持编写插件化程序: 反射可以用于编写插件化程序,使得程序可以在运行时加载和使用插件。通过反射,程序可以动态地加载插件类,并调用其方法和访问其属性。

总的来说,反射使得程序可以在运行时动态地获取和操作类的信息,从而实现更灵活、更动态的编程。它在很多领域都有广泛的应用,包括框架开发、ORM(对象关系映射)、测试框架、插件化开发等。但是需要注意的是,过度使用反射可能会导致性能问题和代码可读性降低,因此在使用反射时需要权衡利弊。

 

反射练习

1.对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去

测试类

public class reflexTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException {
        Student1 s1 = new Student1("小明",19,'男',100);
        Teacher t1 = new Teacher("牛老师",10000);

        saveObject(s1);

    }
    public static void saveObject(Object obj) throws ClassNotFoundException, IOException, IllegalAccessException {
        //获取字节码文件对象
        Class c1 = obj.getClass();

        //创建IO流
        BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\ideaProject\\study\\AdvancedJava3\\src\\itemFanShe\\Test\\a.txt"));

        //获取所有的成员变量
        Field[] declaredFields = c1.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            //获取成员变量的名字
            String name = declaredField.getName();
            //获取成员变量的值
            Object value = declaredField.get(obj);
            //写出数据
            bw.write(name+"="+value);
            bw.newLine(); //换行
        }
        bw.close();
    }
}

学生类

public class Student1 {
    private String name;
    private int age;
    private char sex;
    private int result;

    public Student1(String name, int age, char sex, int result) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.result = result;
    }

    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;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getResult() {
        return result;
    }

    public void setResult(int result) {
        this.result = result;
    }

    @Override
    public String toString() {
        return "Student1{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", result='" + result + '\'' +
                '}';
    }
}

老师类

/**
 * @author hyk~
 */
public class Teacher {
    private String name;
    private int salary;

    public Teacher(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", salary=" + salary +
                '}';
    }
}

2.反射可以跟配置文件结合的方式,动态的创建对象,并调用方法

配置文件 config.properties,其中包含了类名和方法名的配置信息

import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectConfigExample {
    public static void main(String[] args) {
        try {
            // 加载配置文件
            Properties properties = new Properties();
            FileInputStream fis = new FileInputStream("config.properties");
            properties.load(fis);
            fis.close();

            // 从配置文件中获取类名和方法名
            String className = properties.getProperty("class");
            String methodName = properties.getProperty("method");

            // 使用反射动态加载类
            Class<?> clazz = Class.forName(className);
            // 创建类的实例
            Object obj = clazz.getDeclaredConstructor().newInstance();
            // 获取方法对象
            Method method = clazz.getMethod(methodName);
            // 调用方法
            method.invoke(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

config.properties 文件内容如下:

class=com.example.MyClass
method=hello

创建一个 com.example.MyClass 类,其中包含一个名为 hello 的方法

package com.example;

public class MyClass {
    public void hello() {
        System.out.println("Hello, world!");
    }
}

运行 ReflectConfigExample 类时,它会读取配置文件中的类名和方法名,然后使用反射动态地加载类并调用方法。这样就实现了通过配置文件动态地创建对象并调用方法的功能。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CtrlCV 攻城狮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值