【Java】反射概述与详解

 

目录

引言 

一、概述

二、获取Class对象 

三、反射获取构造方法 

代码示例:

四、反射获取成员变量

代码示例:

五、反射获取成员方法

代码示例:

结语


引言 

Java中的反射(Reflection)是一种强大的机制,允许程序在运行时检查和操作其结构和行为。通过反射,程序可以动态地获取类的信息、调用方法、访问字段和创建对象。


一、概述

反射提供了一种在运行时检查类、接口、字段和方法的能力。通过反射,程序可以动态地:

  1. 获取类的所有属性和方法。
  2. 创建类的实例。
  3. 调用类的方法。
  4. 修改类的字段值。

二、获取Class对象 

在Java中,Class对象表示类和接口的元数据。获取Class对象有三种主要方式: 

通过类名获取 

Class<?> clazz = MyClass.class;

通过对象获取

MyClass obj = new MyClass();  
Class<?> clazz = obj.getClass();

通过全限定类名获取(使用Class.forName):

try {  
    Class<?> clazz = Class.forName("com.example.MyClass");  
} catch (ClassNotFoundException e) {  
    e.printStackTrace();  
}

注意:一般来说反射创建class对象通过全限定类名获取最为常用,其第一种通过类名获取常用作为参数来传递,例如:synchronized(类名.class){} 中的锁对象常用这种方式指定。


三、反射获取构造方法 

方法名 说明
Constructor<?>[] getConstructors() 获得所有的构造(只能public修饰)
Constructor<?>[] getDeclaredConstructors()  获得所有的构造(包含private修饰)
Constructor<T> getConstructor(Class<?>... parameterTypes) 获取指定构造(只能public修饰)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定构造(包含private修饰)
newInstance 创建对象
setAccessible 临时取消权限检验

其代码中所用到的Paper类:

import java.io.IOException;

public class Paper {
    private String name;
    private int age;
    public String address;

    public String getAddress() {
        return address;
    }

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

    public void setAddress(String address) {
        this.address = address;
    }

    public Paper() {
    }

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

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

    protected Paper(int age) {
        this.age = age;
    }

    /**
     * 获取
     *
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     *
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     *
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    private String eat(String something) throws IOException,NullPointerException,ClassCastException {
        System.out.println("在吃" + something);
        return "吃饱了";
    }

    private void sleep() {
        System.out.println("正在睡觉");
    }

    public String toString() {
        return "Paper{name = " + name + ", age = " + age + "}";
    }
}

代码示例:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectConstructor {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取class对象
        Class<?> aClass = Class.forName("com.pjk.a1024reflect.Paper");

        //获取构造方法
        //1.获取所有的公共构造方法
        Constructor<?>[] cons1 = aClass.getConstructors();
        for (Constructor<?> constructor : cons1) {
            System.out.println(constructor);
        }
        //2.获取所有的构造方法
        Constructor<?>[] cons2 = aClass.getDeclaredConstructors();
        for (Constructor<?> constructor : cons2) {
            System.out.println(constructor);
        }
        //3.获取单个的公共构造方法
        // ()代表无参
        // (String.class)代表带一个String参数的有参构造
        Constructor<?> con1 = aClass.getConstructor();
        System.out.println(con1);
        //4.获取单个的构造方法
        Constructor<?> con2 = aClass.getDeclaredConstructor(String.class);
        System.out.println(con2);
        Constructor<?> con3 = aClass.getDeclaredConstructor(int.class);
        System.out.println(con3);

        System.out.println(con2.getName());
        System.out.println(con2.getModifiers());

        System.out.println("-------------------------------------------------");

        //利用获取出来的构造方法创建对象
        //1.利用公共构造创建对象
        Paper p1 = (Paper) con1.newInstance();
        System.out.println(p1);
        //2.利用非公共构造创建对象
        //暴力反射:表示临时取消权限检验
        con2.setAccessible(true);
        Paper p2 = (Paper) con2.newInstance("zhangsan");
        System.out.println(p2);
        Paper p3 = (Paper) con3.newInstance(18);
        System.out.println(p3);
    }
}

四、反射获取成员变量

方法名 说明
Field[] getFields() 返回所有成员变量对象的数组(只能拿public的)
Field[] getDeclaredFields() 返回所有成员变量对象的数组,存在就能拿到
Field getField(String name) 返回单个成员变量对象(只能拿public的)
Field getDeclaredField(String name) 返回单个成员变量对象,存在就能拿到
void set(Object obj, Object value) 赋值
Object get(Object obj) 获取值
setAccessible 临时取消权限检验

代码示例:

import java.lang.reflect.Field;

public class ReflectField {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //获取class对象
        Class<?> aClass = Class.forName("com.pjk.a1024reflect.Paper");

        //利用反射获取成员变量
        //1.获取所有公共成员变量
        Field[] fields1 = aClass.getFields();
        for (Field field : fields1) {
            System.out.println(field);
        }
        //2.获取所有成员变量
        Field[] fields2 = aClass.getDeclaredFields();
        for (Field field : fields2) {
            System.out.println(field);
        }
        //3.获取单个公共成员变量
        Field address = aClass.getField("address");
        System.out.println(address);
        //4.获取单个成员变量
        Field name = aClass.getDeclaredField("name");
        System.out.println(name);

        //获取成员变量的修饰符
        System.out.println(name.getModifiers());

        //获取成员变量记录的值
        Paper p = new Paper("洁柔", 10, "广东");
        //暴力反射:表示临时取消权限检验
        name.setAccessible(true);
        String n = (String) name.get(p);
        System.out.println(n);

        //修改对象里面记录的值
        name.set(p, "维达");
        System.out.println(p);
    }
}

五、反射获取成员方法

方法名 说明
Method[] getMethods() 返回所有成员方法对象的数组(只能拿public的)
Method[] getDeclaredMethods() 返回所有成员方法对象的数组,存在就能拿到
Method getMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象(只能拿public的)
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象,存在就能拿到
Object invoke(Object obj, Object... args) 运行方法
setAccessible 临时取消权限检验

注意:其中getMethods()获取成员方法时,包含了其父类的所有public公共方法。

代码示例:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class ReflectMethod {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //获取class对象
        Class<?> aClass = Class.forName("com.pjk.a1024reflect.Paper");

        //利用反射获取成员方法
        //1.获取所有公共成员方法(包含父类的公共成员方法)
        Method[] methods1 = aClass.getMethods();
        for (Method method : methods1) {
            System.out.println(method);
        }
        //2.获取所有的方法
        Method[] methods2 = aClass.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.println(method);
        }
        //3.获取单个方法
        Method method = aClass.getDeclaredMethod("eat", String.class);
        //获取方法的形参
        Parameter[] parameters = method.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        //获取方法抛出的异常
        Class<?>[] exceptionTypes = method.getExceptionTypes();
        for (Class<?> exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }

        //方法运行
        /*
        * invoke:运行方法
        * invoke(Object obj,Object... args)
        * 参数一:用obj对象调用该方法
        * 参数二:调用方法所需形参(没有就不写)
        * */
        Paper p = new Paper("洁柔", 10, "东莞");
        method.setAccessible(true);
        String kfc = (String) method.invoke(p, "KFC");
        System.out.println(kfc);
    }
}

结语

  • 性能:反射通常比直接代码调用慢,因为它涉及额外的检查和类型转换。
  • 安全性:反射可以绕过Java的访问控制机制,可能导致意外的副作用或安全问题。
  • 异常处理:反射操作可能抛出多种检查异常(如ClassNotFoundException、NoSuchMethodException、IllegalAccessException等),需要妥善处理。

掌握反射,Java开发者可以编写更加灵活和动态的代码,但也需要谨慎使用,以避免潜在的性能和安全问题。 

 

猜你喜欢

转载自blog.csdn.net/qq_52924376/article/details/143213544