Java阶段十:反射

本文深入探讨了Java的反射机制,包括获取Class对象的三种方式及其区别,详细阐述了如何通过反射获取构造方法、成员变量和成员方法,并通过实例展示了反射在越过泛型检查和运行配置文件指定方法上的应用。总结了反射机制在提高程序灵活性方面的强大功能。
摘要由CSDN通过智能技术生成

目录

反射

获取Class类对象的三种方式

获取Class类对象的三种方式的区别

一、反射获取构造方法对象的方法

二、反射获取成员变量的方法

三、反射获取成员方法的方法

反射的案例

一、越过泛型检查

二、通过反射运行配置文件中指定类的指定方法

总结

反射


概念:在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展。

简单来说,就是在程序运行状态中,能够获取到这个类的所有属性和方法(包括私有属性、方法以及构造器),这种动态获取信息以及动态调用对象方法的功能就称为反射机制。通过反射,可以获取到类中的任何东西。

获取Class类对象的三种方式

  • 类名.class属性

  • 对象名.getClass()方法

  • Class.forName(全类名)方法

案例:

//学生类
public class Student {
    //成员变量:一个私有,一个默认,一个公共
    private String name;
    int age;
    public String address;

    //构造方法:一个私有,一个默认,两个公共
    public Student() {
    }

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

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

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

    //成员方法:一个私有,四个公共
    private void function() {
        System.out.println("function");
    }

    public void method1() {
        System.out.println("method");
    }

    public void method2(String s) {
        System.out.println("method:" + s);
    }

    public String method3(String s, int i) {
        return s + "," + i;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
//在这里使用的是上述自定义的Student类,其实可以是任意类
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //使用类的class属性来获取该类对应的Class对象
        Class<Student> c1 = Student.class;
        System.out.println(c1);
        Class<Student> c2 = Student.class;
        System.out.println(c1 == c2);
        System.out.println("-----------");

        //调用对象的getClass()方法,返回该对象所属类对应的Class对象
        Student s = new Student();
        Class<? extends Student> c3 = s.getClass();
        System.out.println(c1 == c3);
        System.out.println("-----------");

        //使用Class类中的静态方法forName(String className)
        Class<?> c4 = Class.forName("com.test.Student");
        System.out.println(c1 == c4);
    }
}

界面展示:

获取Class类对象的三种方式的区别

创建一个对象Person

public class Person {
 
    static {System.out.println("Person:静态代码块");}
 
    {System.out.println("Person:动态代码块");}
 
    public Person(){
        System.out.println("Person:构造方法");
    }
}

构建单元测试

public class GetClassTest {
 
    @Test
    public void test1(){
        Class<?> cp1 = Person.class;
    }
 
    @Test
    public void test2() throws ClassNotFoundException {
        Class<?> cp2 = Class.forName("com.test.Person");
    }
 
    @Test
    public void test3() {
        Class<?> cp3 = new Person().getClass();
    }
}

执行结果:

  • 第一个单元测试:没打印任何内容
  • 第二个单元测试:打印了“静态方法”
  • 第三个单元测试:打印出了全部内容

总结:

  1. 通过类名.class属性获取对象的Class对象,不会调用任何的代码块和代码
  2. 通过Class.forName(全类名)方法获取对象的Class对象,会调用静态代码块的内容
  3. 通过对象名.getClass()方法获取对象的Class对象,因为要先实例化对象,所以会打印全部内容

一、反射获取构造方法对象的方法

方法名说明
Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组
Constructor<T> getConstructor(Class<?>... parameterTypes)返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)返回单个构造方法对象

Constructor类用于创建对象的方法:

T newInstance(Object...initargs)根据指定的构造方法创建对象

 案例:

//使用的是上述自定义的Student类
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象
        Class<?> c = Class.forName("com.test.Student");

        //返回反映由该Class对象表示的类声明的所有构造函数的Constructor对象的数组
        Constructor<?>[] cons = c.getDeclaredConstructors();
        for (Constructor con : cons){
            System.out.println(con);
        }
        System.out.println("-------------");

        //Constructor<T> getConstructor(Class<?>... parameterTypes)
        // 返回一个 Constructor对象,该对象反映由该Class对象表示的类的指定公共构造函数
        Constructor<?> con = c.getConstructor();

        //Constructor提供了一个类的单个构造函数的信息和访问权限
        //T newInstance(Object... initargs)使用由此Constructor对象表示的构造函数,
        Object obj = con.newInstance();
        System.out.println(obj);
    }
}

界面展示:

注意事项:

  • 基本数据类型也可以通过.class得到对应的Class类型

  • public void setAccessible(boolean flag):值为true,取消访问检查,访问私有时使用 (暴力反射)

二、反射获取成员变量的方法

方法名说明
Field[] getFields()返回所有公共成员变量对象的数组
Field[] getDeclaredFields()返回所有成员变量对象的数组
Field getField(String name)返回单个公共成员变量对象
Field getDeclaredField(String name)返回单个成员变量对象

Field类用于给成员变量赋值的方法:

void set(Object obj,Object value)给obj对象的成员变量赋值为value

案例:

//使用的是上述自定义的Student类
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Class对象
        Class<?> c = Class.forName("com.test.Student");

        //Field[] getDeclaredFields() 返回一个Field对象的数组,反映了由该Class对象表示的类或接口声明的所有字段
        Field[] fields = c.getDeclaredFields();
        for(Field field : fields) {
            System.out.println(field);
        }
        System.out.println("--------");

        //Field getField(String name) 返回一个Field对象,该对象反映由该Class对象表示的类或接口的指定公共成员字段
        Field addressField = c.getField("address");

        //获取无参构造方法创建对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        //Field提供有关类或接口的单个字段的信息和动态访问
        //void set(Object obj, Object value)将指定的对象参数中由此Field对象表示的字段设置为指定的新值
        addressField.set(obj,"西安"); //给obj的成员变量addressField赋值为西安
        System.out.println(obj);
    }
}

界面展示:

三、反射获取成员方法的方法

方法名说明
Method[] getMethods()返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods()返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>... parameterTypes)返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes)返回单个成员方法对象

Method类用于执行方法的方法:

Object invoke(Object obj,Object... args)调用obj对象的成员方法,参数是args,返回值是Object类型

案例:

//使用的是上述自定义的Student类
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        //获取Class对象
        Class<?> c = Class.forName("com.test.Student");

        //Method[] getDeclaredMethods() 返回一个包含方法对象的数组,方法对象反映由Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法
        Method[] methods = c.getDeclaredMethods();
        for(Method method : methods) {
            System.out.println(method);
        }
        System.out.println("--------");

        //Method getMethod(String name, Class<?>... parameterTypes) 返回一个方法对象,该对象反映由该Class对象表示的类或接口的指定公共成员方法
        Method m = c.getMethod("method1");

        //获取无参构造方法创建对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        //在类或接口上提供有关单一方法的信息和访问权限
        //Object invoke(Object obj, Object... args) 在具有指定参数的指定对象上调用此方法对象表示的基础方法
        //Object:返回值类型,obj:调用方法的对象,args:方法需要的参数
        m.invoke(obj);
    }
}

界面展示:

反射的案例


一、越过泛型检查

代码实现:通过反射技术,向一个泛型为Integer的集合中添加一些字符串数据

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //创建集合
        ArrayList<Integer> array = new ArrayList<Integer>();

        //获取Class类对象
        Class<? extends ArrayList> c = array.getClass();
        //获取ArrayList中的add方法
        Method m = c.getMethod("add", Object.class);

        //赋值
        m.invoke(array,"hello");
        m.invoke(array,"world");
        m.invoke(array,"java");

        System.out.println(array);
    }
}

界面展示:

二、通过反射运行配置文件中指定类的指定方法

代码实现:

class文件的设计:

//学生类
public class Student {
    public void study(){
        System.out.println("好好学习,天天向上!");
    }
}
//老师类
public class Teacher {
    public void teach(){
        System.out.println("用爱成就每一位学员!");
    }
}
public class ReflectTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //文件中的内容读到集合
        Properties prop = new Properties();
        FileReader fr = new FileReader("idea_test_9\\class.txt");
        prop.load(fr);
        fr.close();

        //获取集合中的数据
        String className = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");

        //通过反射使用
        Class<?> c = Class.forName(className);

        //指定构造方法创建对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        //获取成员方法
        Method m = c.getMethod(methodName);
        //调用成员方法
        m.invoke(obj);
    }
}

界面展示:

总结


        反射部分的主要方法就介绍到这里了,可以发现反射的使用比较特殊,所实现的功能也是之前看似不可能实现的。这正是反射的强大之处,在此博主只是学习到了该部分的皮毛知识,对于具体的操作以及运用还需慢慢研究,学习是一个持续的过程,加油,为了更好的明天而战!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

South.return

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

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

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

打赏作者

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

抵扣说明:

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

余额充值