java--反射

本文深入讲解Java反射机制,包括如何通过反射访问类的构造方法、方法及成员变量,演示了如何利用反射创建对象、调用方法及修改成员变量,揭示了反射调用与普通调用的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

反射

通过java的反射机制,可以在程序中访问已经加载到JVM中的java对象的描述,实现访问、检测、和修改描述java对象本身信息的功能,它是字java.lang.reflect包下的,并且想要调用访问信息的方法,就要得到class类的对象。 

反射可访问的主要描述信息

组成部分访问方法返回值类型说明
包路径getPackage()Package对象获得该类的存放路径
类名称getName()String对象获得该类的名称
继承类getSuperclass()Class对象获得该类继承的类
实现接口getInterfaces()Class型数组获得该类所实现的所有接口
构造方法getConstructors()Constructor型数组获得所有权限为public的构造方法
getConstructor(Class<?>...parameterTypes)Constructor对象获得权限为public的指定构造方法
getDeclaredConstructors()Constructor型数组获得所有构造方法,按声明顺序返回
getDeclaredConstructors(Class<?>...parameterTypes)Constructor对象获取指定构造方法
方法getMethods()Method型数组获得所有权限为public的方法
getMethod(String name,Class<?>...parameterTypes)Method对象获得权限为public的指定方法
getDeclaredMethods()Method型数组获得所有方法,按照声明顺序返回
getDeclaredMethods(String name,Class<?>...parameterTypes)Method对象获得指定方法
成员变量getFileds()Filed型数组获得所有权限为public的成员变量
getFiled(String name)Filed对象获得权限为public的指定成员变量
getDeclaredFileds()Filed型数组获得所有的成员变量,按照声明顺序返回
getDeclaredFiled(String name)Filed对象获得指定的成员变量
内部类getClasses()Class型数组获得所有权限为public的内部类
getDeclaredClasses()Class型数组获得所有内部类
内部类的声明getDeclaringClass()Class对象如果该类为内部类,则返回它的成员类,否则返回null

访问构造方法

组成部分访问方法返回值类型说明
构造方法getConstructors()Constructor型数组获得所有权限为public的构造方法
getConstructor(Class<?>...parameterTypes)Constructor对象获得权限为public的指定构造方法
getDeclaredConstructors()Constructor型数组获得所有构造方法,按声明顺序返回
getDeclaredConstructors(Class<?>...parameterTypes)Constructor对象获取指定构造方法

Constructor常用方法

方法说明
isVarArgs()查看该构造方法是否允许带有可变数量的参数,如果允许则返回true,否则返回false
getParameterTypes()按照声明顺序以Class数组的形式获得该构造方法的各个参数的类型
getException()以Class数组的形式获得该构造方法可能抛出的异常类型
setAccessible(boolean flag)如果该构造方法的权限为private,默认为不允许通过反射利用newInstance(Object...initargs)方法创建对象。如果执行该方法,并将入口参数设为true,则允许创建
getModifiers()获得可以解析出该构造方法所采用修饰符的整数
newInstance(Object...initargs)通过该构造方法利用指定参数创建一个该类的对象,如果未设置参数则表示采用默认无参数的构造方法

调用getModifiers()返回的对象可以判断该对象是否被某修饰符所修饰,如:isPublic(方法返回的对象),可以判断出是否被public所修饰,还有很多类似的方法,我就不一一说明了,常见的修饰符基本上都有哦。

方法演示

创建几个需要访问的构造方法

public class Example1 {
    private Example1() {
    }
    public Example1(String...S) {
        System.out.println("可变参数的长度:"+S.length);
    }
    private Example1(String s,int i) {
    }
}

main方法 

import java.lang.reflect.Constructor;

public class Example1Test {
    public static void main(String[] args) {
        Example1 e = new Example1("jack", "rose","jim");
        Class<? extends Example1> clazz = e.getClass();
        //获得所有构造方法
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            boolean b=true;
            while (b){
                try {
                    //是否允许带有可变参数,是为true
                    System.out.println("是否允许带有可变参数:"+constructor.isVarArgs());
                    //获取所有参数类型
                    Class<?>[] types = constructor.getParameterTypes();
                    System.out.println("参数类型为:");
                    for (Class<?> type : types) {
                        System.out.println(type);
                    }
                    //获取所有可能出现的异常类型
                    Class<?>[] exceptions = constructor.getExceptionTypes();
                    System.out.println("异常类型:");
                    for (Class<?> exception : exceptions) {
                        System.out.println(exception);
                    }
                    b=false;
                }catch (Exception ee){
                    System.out.println("解决私有构造方法不能访问的问题,需要把setAccessible设置为true");
                    constructor.setAccessible(true);
                }
            }

        }
    }
}

结果

可变参数的长度:3
是否允许带有可变参数:false
参数类型为:
异常类型:
是否允许带有可变参数:true
参数类型为:
class [Ljava.lang.String;
异常类型:
是否允许带有可变参数:false
参数类型为:
class java.lang.String
int
异常类型:

访问方法

组成部分访问方法返回值类型说明
方法getMethods()Method型数组获得所有权限为public的方法
getMethod(String name,Class<?>...parameterTypes)Method对象获得权限为public的指定方法
getDeclaredMethods()Method型数组获得所有方法,按照声明顺序返回
getDeclaredMethods(String name,Class<?>...parameterTypes)Method对象获得指定方法

Method类常用方法

方法说明
getName()获得该方法的名称
getParameterTypes()按照声明顺序以Class数组的形式获得该方法的各个参数类型
getReturnType()以Clss对象的形式获得该方法的返回值的类型
getExceptionTypes()以Class数组的形式获得该方法可能抛出的异常类型
invoke(Object obj,Object...args)利用指定的参数args执行指定对象obj中的该方法,返回值为Object类型
isVarArgs()查看该构造方法是否允许带有可变数量的参数,如果允许则返回true,否则返回false
getModifiers()获得可以解析出该方法所采用修饰符的整数

代码演示

创建一些需要访问的方法

public class Example2 {
    static void staticMethod(){
        System.out.println("执行staticMethod方法");
    }
    public int publicMethod(int i){
        System.out.println("执行publicMethod方法");
        return i*100;
    }
    protected int protectedMethod(String s,int i){
        System.out.println("执行protectedMethod方法");
        return Integer.parseInt(s)+i;
    }
    private String privateMethod(String...s){
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < s.length; i++) {
            buffer.append(s[i]);
        }
        return buffer.toString();
    }
}

main方法 

import java.lang.String;
import java.lang.reflect.Method;

public class Example2Test {
    public static void main(String[] args) {
        Example2 e = new Example2();
        Class<? extends Example2> clazz = e.getClass();
        //获得所有方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            //获得方法名称
            System.out.println("方法名称为:"+method.getName());
            //获得参数类型
            Class<?>[] types = method.getParameterTypes();
            System.out.println("参数类型为:");
            for (Class<?> type : types) {
                System.out.println(type);
            }
            //获取方法返回值类型
            Class<?> returnType = method.getReturnType();
            System.out.println("返回值类型为:"+returnType);
            //是否允许可变参数
            System.out.println("是否允许可变参数:"+method.isVarArgs());
            //判断该方法名字是否一致,如果一致,就调用该方法
            boolean b=true;
            while (b){
                try{
                    b=false;
                    if("staticMethod".equals(method.getName())){
                        //调用方法,这个是无参的方法,因此只要写上方法所在的对象就可以了
                        method.invoke(e);
                    }else if("publicMethod".equals(method.getName())){
                        //调用方法,这个是有参的方法,因此写上方法所在的对象,再写上要传入的参数,根据方法的参数,传递参数哟
                        System.out.println("返回值:"+method.invoke(e, 10));
                    }else if("protectedMethod".equals(method.getName())){
                        System.out.println("返回值:"+method.invoke(e, "7", 100));
                    }else if("privateMethod".equals(method.getName())){
                        //当参数为可变参数时,需要把反射调用方法的第二个参数写成二维数组的形式
                        Object[] obj=new Object[]{new String[]{"oh", "my", "god", "!"}};
                        System.out.println("返回值:"+method.invoke(e,obj));
                    }
                }catch (Exception ee){
                    //为了访问私有方法,把该方法设置为true
                    method.setAccessible(true);
                    b=true;
                }
            }
        }
    }
}

结果

方法名称为:staticMethod
参数类型为:
返回值类型为:void
是否允许可变参数:false
执行staticMethod方法
方法名称为:publicMethod
参数类型为:
int
返回值类型为:int
是否允许可变参数:false
执行publicMethod方法
返回值:1000
方法名称为:protectedMethod
参数类型为:
class java.lang.String
int
返回值类型为:int
是否允许可变参数:false
执行protectedMethod方法
返回值:107
方法名称为:privateMethod
参数类型为:
class [Ljava.lang.String;
返回值类型为:class java.lang.String
是否允许可变参数:true
返回值:ohmygod!

注意:可变参数的方法,在反射调用方法时,是需要把参数装入到二维数组中的。

访问成员变量

组成部分访问方法返回值类型说明
成员变量getFileds()Filed型数组获得所有权限为public的成员变量
getFiled(String name)Filed对象获得权限为public的指定成员变量
getDeclaredFileds()Filed型数组获得所有的成员变量,按照声明顺序返回
getDeclaredFiled(String name)Filed对象获得指定的成员变量

Filed类的常用方法

方法说明
getName()获得该成员变量的名称
getType()获得表示该成员变量类型的Class对象
get(Object obj)获得指定对象obj中成员变量的值,返回值为Object型
set(Object obj,Object value)将指定对象obj中成员变量的值设置为value
getInt(Object obj)获得指定对象obj中类型为int的成员变量的值
setInt(Object obj,int i)将指定对象obj中类型为int的常用变量的值设置为i
getFloat(Object obj)获得指定对象obj中类型为float的成员变量的值
setFloat(Object obj,float f)将指定对象obj中类型为float的常用变量的值设置为f
getBoolean(Object obj)获得指定对象obj中类型为boolean的成员变量的值
SetBoolean(Object obj,boolean b)将指定对象obj中类型为boolean的常用变量的值设置为b
setAccessible(boolean flag)此方法可以设置是否忽略权限直接访问private等私有权限的成员变量
getModifiers()获得可以解析出该成员变量所采用的修饰符的整数

代码演示

声明一些需要访问的成员变量

public class Example3 {
    int i;
    float f;
    protected boolean b;
    private String s;
}

main方法 

import java.lang.reflect.Field;

public class Example3Test {
    public static void main(String[] args) {
        Example3 e = new Example3();
        //获得class对象,这样可以访问需要的信息
        Class clazz = e.getClass();
        //获得所有成员变量
        Field[] fields = clazz.getDeclaredFields();
        //遍历成员变量数组
        for (Field field : fields) {
            //获得成员变量的名称
            System.out.print("名称为:"+field.getName()+"  ");
            //获得成员变量的类型
            Class type = field.getType();
            System.out.println("类型为:"+type);
            boolean flag=true;
            while (flag){
                try {
                    flag=false;
                    //获得没有修改前的成员变量值
                    System.out.println("获得修改前的值"+field.get(e));
                    //判断为什么类型的成员变量,并为其赋值
                    if(type.equals(int.class)){
                        //为该成员变量赋值
                        field.set(e,20);
                    }else if(type.equals(float.class)){
                        field.set(e,199.5f);
                    }else if(type.equals(boolean.class)){
                        field.set(e,true);
                    }else {
                        field.set(e,"idea");
                    }
                    System.out.println("获得修改过后的值:"+field.get(e));
                }catch (Exception ee){
                    System.out.println("抛出私有成员变量不可访问异常,把setAccessible设置为true就可以访问了");
                    field.setAccessible(true);
                    flag=true;
                }
            }
        }
    }
}

结果

名称为:i  类型为:int
获得修改前的值0
获得修改过后的值:20
名称为:f  类型为:float
获得修改前的值0.0
获得修改过后的值:199.5
名称为:b  类型为:boolean
获得修改前的值false
获得修改过后的值:true
名称为:s  类型为:class java.lang.String
抛出私有成员变量不可访问异常,把setAccessible设置为true就可以访问了
获得修改前的值null
获得修改过后的值:idea

总结

通过反射访问,方法、构造方法、成员变量,你可以发现这与普通调用之间的区别,区别在于反射调用,只要设置setAccessible,就可以访问私有的成员,而普通的调用是不可以访问的,并且普通的调用不能够看到成员的信息,而反射调用可以。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值