java:Class类与java反射

本文深入探讨Java反射机制,通过Object类的getClass()方法获取Class对象,进而访问类信息、构造方法、成员变量和方法。详细介绍了如何通过Constructor、Method和Field类进行构造方法、成员变量和方法的访问及操作,包括参数类型、异常处理、权限设置等。并提供实例代码展示实际操作过程。

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

java:Class类与java反射

1 介绍

通过java反射机制,可以在程序中访问已经装载到JVM中的java对象的描述,实现访问、检测和修改描述java对象本身信息的功能。java反射机制的功能,在java.lang.reflect包中提供了对该功能的支持。

2 初识

所有java类均继承了Object类,在Object类中定义了一个getClass()方法,该方法返回一个类型为Class的对象,如下:

public class RefUtils {
    public static void main(String[] args) {
        RefUtils ins_r=new RefUtils();
        Class<? extends RefUtils> r=ins_r.getClass();
    }
}

利用Class类的对象r,可以访问用来返回该对象的类对象的描述信息,信息如下:

组成部分: 访问方法: 返回值类型: 说明:

包路径: getPackage():Package对象:获得该类的存放路径

类名称: getName():String对象:获得该类的名称

继承类: getSuperclass():Class对象:获得该类继承的类

实现接口: getInterfaces():Class型数组:获得该类实现的所有接口
在这里插入图片描述

package com.base;

import java.util.Arrays;

public class RefUtils {
    public static void main(String[] args) {
        RefUtils ins_r=new RefUtils();
        Class<? extends RefUtils> r=ins_r.getClass();
        System.out.println(r.getPackage());
        System.out.println(r.getName());
        System.out.println(r.getSuperclass());
        System.out.println(Arrays.toString(r.getInterfaces()));
    }
}

class R{}

class R2{}

interface MyR{}

interface MyR2{}
package com.base
com.base.RefUtils
class java.lang.Object
[]

java中没有多继承(类),只有多实现(接口)
在这里插入图片描述

package com.base
com.base.RefUtils
class com.base.R
[interface com.base.MyR, interface com.base.MyR2]

构造方法:

getConstructors():Constructor型数组:获得所有权限为public的构造方法
getConstructor(Class<?>… parameterTypes):Constructor对象:获得权限为public的指定构造方法

拓展:java方法中,把多个参数聚合为数组的方式:

public class RefUtils extends R implements MyR,MyR2{
    public static void main(String[] args) {
        RefUtils.aaa("1223","2");
    }
    public static void aaa(String... tys){
        System.out.println(Arrays.toString(tys));
    }
}
[1223, 2]

错误方式:
在这里插入图片描述
在这里插入图片描述
JavaScript:扩展运算符

扩展运算符(spread)是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
在这里插入图片描述
在这里插入图片描述
getDeclaredConstructors():Constructor型数组:获得所有构造方法,按声明顺序返回
getDeclaredConstructor(Class<?>… parameterTypes)():Constructor对象:获得指定构造方法

方法:

getMethods():Method型数组:获得所有权限为public的方法

getMethod(String name, Class<?>… parameterTypes)():Method对象:获得权限为public的指定方法

getDeclaredMethods():Method型数组:获得所有方法,按声明顺序返回

getDeclaredMethod(String name, Class<?>… parameterTypes)():Method对象:获得指定方法

成员变量:

getFields():Field型数组:获得所有权限为public的成员变量

getField(String name)():Field对象:获得权限为public的指定成员变量

getDeclaredFields():Field型数组:获得所有成员变量,按声明顺序返回

getDeclaredField(String name)():Field对象:获得指定成员变量

内部类:

getClasses():Class型数组:获得所有权限为public的内部类

getDeclaredClasses():Class型数组:获得所有内部类

内部类的声明类:

getDeclaringClass():Class对象:如果该类为内部类,则返回它的成员类,否则返回null

说明:

在通过getFields()和getMethods()方法依次获得权限为public的成员变量和方法时,将包含从超类中继承到的成员变量和方法;而通过方法getDeclaredFields()和getDeclaredMethods()只是获得在本类中定义的所有成员变量和方法。

3 访问构造方法

在通过下列一组方法访问构造方法时,将返回Constructor类型的对象或数组。每个Constructor对象代表一个构造方法,利用Constructor对象可以操纵相应的构造方法。

getConstructors():Constructor型数组:获得所有权限为public的构造方法
getConstructor():getConstructor(Class<?>… parameterTypes):Constructor对象:获得权限为public的指定构造方法
getDeclaredConstructors():Constructor型数组:获得所有构造方法,按声明顺序返回
getDeclaredConstructor(Class<?>… parameterTypes)():Constructor对象:获得指定构造方法

如果是访问指定的构造方法,需要根据该构造方法的入口参数的类型来访问。例如,访问一个入口参数类型依次为String和int型构造方法,通过下面两种方式均可以实现。

objectClass.getDeclaredConstructor(String.class,int.class);
objectClass.getDeclaredConstructor(new Class[]{String.class,int.class});

Constructor类中提供的常用方法如下 (结构:方法+说明)

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

通过java.lang.reflect.Modifier类可以解析出getModifiers()方法的返回值所表示的修饰符信息,在该类中提供了一系列用来解析的静态方法,既可以查看是否被指定的修饰符修饰,还可以以字符串的形式获得所有修饰符。该类常用静态方法如下 (结构:静态方法+说明)

isPublic(int mod):查看是否被public修饰符修饰,如果是则返回true,否则返回false
isProtected(int mod):查看是否被protected修饰符修饰,如果是则返回true,否则返回false
isPrivate(int mod):查看是否被private修饰符修饰,如果是则返回true,否则返回false
isStatic(int mod):查看是否被static修饰符修饰,如果是则返回true,否则返回false
isFinal(int mod):查看是否被final修饰符修饰,如果是则返回true,否则返回false
toString(int mod):以字符串的形式返回所有修饰符

例如,判断对象constructor所代表的构造方法是否被private修饰,以及以字符串形式获得该构造方法的所有修饰符的典型代码如下:

int modifiers=constructor.getModifiers();
boolean isEmbellishByPrivate=Modifier.isPrivate(modifiers);
String embellishment=Modifier.toString(modifiers);

例子:访问构造方法

package com.base2;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.Arrays;


public class Construc {
    String s;
    int i1,i2,i3;
    private Construc(){}
    protected Construc(String s,int i1){
        this.s=s;
        this.i1=i1;
    }
    public Construc(String... strs)throws NumberFormatException{
        if(0<strs.length)
            i1=Integer.parseInt(strs[0]);
        if(1< strs.length)
            i2=Integer.parseInt(strs[1]);
        if(2< strs.length)
            i3=Integer.parseInt(strs[2]);
    }
    public void print(){
        System.out.println("s="+s);
        System.out.println("i1="+i1);
        System.out.println("i2="+i2);
        System.out.println("i3="+i3);
    }

    public static void main(String[] args) {
        Construc c=new Construc("10","20","30");
        Class<? extends Construc> e=c.getClass();
        //获得所有构造方法
        Constructor<?>[] c1=e.getDeclaredConstructors();
        for (Constructor<?> constructor : c1) {
            System.out.println("查看是否允许带有可变数量的参数:"+constructor.isVarArgs());
            System.out.println("该构造方法的入口参数类型依次为:");
            Class<?>[] parameterTypes=constructor.getParameterTypes();
            //注意:String...的方法参数形式,既可以传入多个String参数,也可以传入String[] 数组
            System.out.println(Arrays.asList(parameterTypes));
            System.out.println("该构造方法可能抛出的异常类型为:");
            Class<?>[] exceptionTypes=constructor.getExceptionTypes();
            System.out.println(Arrays.toString(exceptionTypes));
            System.out.println("该方法的权限修饰:");
            System.out.println(Modifier.isPrivate(constructor.getModifiers()));
            System.out.println(Modifier.isProtected(constructor.getModifiers()));
            System.out.println(Modifier.isPublic(constructor.getModifiers()));
            //
            Construc cc=null;
            while(cc==null){

                //通过执行具有可变数量参数的构造方法创建对象
                try {
                    if(Modifier.isPublic(constructor.getModifiers())){
                        System.out.println("开始public:");
                        Object[] parameters=new Object[]{new String[]{"100","200","300"}};
                        cc= (Construc) constructor.newInstance(parameters);
                    }else if(Modifier.isProtected(constructor.getModifiers())){
                        System.out.println("开始protected:");
                        //通过执行具有两个参数的构造方法创建对象
                        cc=(Construc) constructor.newInstance("88",10);
                    }else{
                        System.out.println("开始private:");

                        //通过执行默认没有参数的构造方法创建对象
                        cc=(Construc) constructor.newInstance();
                    }
                } catch (InstantiationException ex) {
                    ex.printStackTrace();
                } catch (IllegalAccessException ex) {
                    ex.printStackTrace();
                } catch (InvocationTargetException ex) {
                    ex.printStackTrace();
                }
            }
            if(cc!=null){
                cc.print();
                System.out.println();
            }
            System.out.println("------------------------");
        }
    }
}
查看是否允许带有可变数量的参数:true
该构造方法的入口参数类型依次为:
[class [Ljava.lang.String;]
该构造方法可能抛出的异常类型为:
[class java.lang.NumberFormatException]
该方法的权限修饰:
false
false
true
开始public:
s=null
i1=100
i2=200
i3=300

------------------------
查看是否允许带有可变数量的参数:false
该构造方法的入口参数类型依次为:
[class java.lang.String, int]
该构造方法可能抛出的异常类型为:
[]
该方法的权限修饰:
false
true
false
开始protected:
s=88
i1=10
i2=0
i3=0

------------------------
查看是否允许带有可变数量的参数:false
该构造方法的入口参数类型依次为:
[]
该构造方法可能抛出的异常类型为:
[]
该方法的权限修饰:
true
false
false
开始private:
s=null
i1=0
i2=0
i3=0

------------------------

Process finished with exit code 0

4 访问成员变量

在通过下列一组方法访问成员变量时,将返回Field类型的对象或数组。每个Field对象代表一个成员变量,利用Field对象可以操纵相应的成员变量。

getFields()
getField(String name)
getDeclaredFields()
getDeclaredField(String name)

如果是访问指定的成员变量,可以通过该成员变量的名称来访问。例如,访问一个名称为birthday的成员变量,访问方法如下:

object.getDeclaredField("birthday");

Field类中提供的常用方法如下(结构:方法+说明):
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 z):将指定对象obj中类型为boolean的成员变量的值设置为z
setAccessible(boolean flag):此方法可以设置是否忽略权限限制直接访问private等私有权限的成员变量
getModifiers():获得可以解析出该成员变量所采用修饰符的整数

package com.base2;

import java.lang.reflect.Field;

public class Metho {
    int i;
    public float f;
    protected boolean b;
    private String s;
    public static void main(String[] args) throws IllegalAccessException {
        Metho m=new Metho();
        Class<? extends Metho> c=m.getClass();
        //获得所有成员变量
        Field[] fs=c.getDeclaredFields();
        for (Field f : fs) {
            System.out.println(f);
            System.out.println("名称为:"+f.getName());
            System.out.println("类型为:"+f.getType());
            boolean isFlag=true;
            while(isFlag){
                //如果该成员变量的访问权限
                isFlag=false;
                //获得成员变量值
                //获得修改前的值,需要抛出IllegalAccessException异常
                System.out.println("修改前的值为:"+f.get(m));
                if(f.getType().equals(int.class)){
                    //判断成员变量的类型是否为int型
                    System.out.println("利用方法setInt()修改成员变量的值");
                    f.setInt(m,27);
                }else if(f.getType().equals(float.class)){
                    System.out.println("利用方法setFloat()修改成员变量的值");
                    f.setFloat(m,9.99F);
                }else if(f.getType().equals(boolean.class)){
                    System.out.println("利用方法setBoolean()修改成员变量的值");
                    f.setBoolean(m,true);
                }else{
                    System.out.println("利用方法set()修改成员变量的值");
                    f.set(m,"XiaoXu");
                }
                //获得成员变量值
                System.out.println("修改后的值为:"+f.get(m));
            }
            System.out.println("-----------------");
        }
    }
}
int com.base2.Metho.i
名称为:i
类型为:int
修改前的值为:0
利用方法setInt()修改成员变量的值
修改后的值为:27
-----------------
public float com.base2.Metho.f
名称为:f
类型为:float
修改前的值为:0.0
利用方法setFloat()修改成员变量的值
修改后的值为:9.99
-----------------
protected boolean com.base2.Metho.b
名称为:b
类型为:boolean
修改前的值为:false
利用方法setBoolean()修改成员变量的值
修改后的值为:true
-----------------
private java.lang.String com.base2.Metho.s
名称为:s
类型为:class java.lang.String
修改前的值为:null
利用方法set()修改成员变量的值
修改后的值为:XiaoXu
-----------------

Process finished with exit code 0

5 访问方法

通过下列一组方法访问方法时,将返回Method类型的对象或数组。每个Method对象代表一个方法,利用Method对象可以操作相应的方法。

getMethods():Method型数组:获得所有权限为public的方法
getMethod(String name, Class<?>… parameterTypes)():Method对象:获得权限为public的指定方法
getDeclaredMethods():Method型数组:获得所有方法,按声明顺序返回
getDeclaredMethod(String name, Class<?>… parameterTypes)():Method对象:获得指定方法

如果是访问指定的方法,需要根据该方法的名称和入口参数的类型来访问。例如,访问一个名称为print、入口参数依次为String和int型的方法,以下两种方式均可以:

objectClass.getDeclaredMethod("print",String.class,int.class)
objectClass.getDeclaredMethod("print",new Class[]{String.class,int.class})

Method类中提供的常用方法如下(结构:方法+说明):

getName():获得该方法的名称
getParameterTypes():按照声明顺序以Class数组的形式获得该方法的各个参数的类型
getReturnType():以Class对象的形式获得该方法的返回值类型
getExceptionTypes():以Class数组的形式获得该方法可能抛出的异常类型
invoke(Object obj,Object… args):利用指定参数args执行指定对象obj中的该方法,返回值为Object型
getModifiers():获得可以解析出该方法所采用的修饰符的整数

package com.base2;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class Met {
    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)throws NumberFormatException{
        System.out.println("执行protectedMethod()方法");
        return Integer.valueOf(s)+i;
    }
    private String privateMethod(String... strs){
        System.out.println("执行privateMethod()方法");
        StringBuffer sb=new StringBuffer();
        for (String str : strs) {
            sb.append(str);
        }
        return sb.toString();
    }

    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        Met k=new Met();
        Class<? extends Met> h=k.getClass();
        Method[] ms=h.getDeclaredMethods();
        for (Method m : ms) {
            System.out.println("名称为:"+m.getName());
            System.out.println("是否允许带有可变数量的参数:"+m.isVarArgs());
            System.out.println("入口参数类型依次为:");
            Class<?>[] parameterTypes=m.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.print("  "+parameterType);
            }
            //获得方法返回值类型
            System.out.println("返回值类型为:"+m.getReturnType());
            System.out.println("可能抛出的异常类型有:"+ Arrays.toString(m.getExceptionTypes()));
            boolean isTrue=true;
            while(isTrue){
                isTrue=false;
                if("staticMethod".equals(m.getName())){
                    m.invoke(k);
                }else if("publicMethod".equals(m.getName())){
                    System.out.println("返回值为:"+m.invoke(k,189));
                }else if("protectedMethod".equals(m.getName())){
                    System.out.println("返回值为:"+m.invoke(k,"9",2));
                }else if("privateMethod".equals(m.getName())){
                    Object[] p=new Object[]{
                      new String[]{
                              "X","I"
                      }
                    };
                    System.out.println("返回值为:"+m.invoke(k,p));
                }
            }
            System.out.println("------------------------");
        }
    }
}
名称为:main
是否允许带有可变数量的参数:false
入口参数类型依次为:
  class [Ljava.lang.String;返回值类型为:void
可能抛出的异常类型有:[class java.lang.reflect.InvocationTargetException, class java.lang.IllegalAccessException]
------------------------
名称为:staticMethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
返回值类型为:void
可能抛出的异常类型有:[]
执行staticMethod()方法
------------------------
名称为:privateMethod
是否允许带有可变数量的参数:true
入口参数类型依次为:
  class [Ljava.lang.String;返回值类型为:class java.lang.String
可能抛出的异常类型有:[]
执行privateMethod()方法
返回值为:XI
------------------------
名称为:publicMethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
  int返回值类型为:int
可能抛出的异常类型有:[]
执行publicMethod()方法
返回值为:18900
------------------------
名称为:protectedMethod
是否允许带有可变数量的参数:false
入口参数类型依次为:
  class java.lang.String  int返回值类型为:int
可能抛出的异常类型有:[class java.lang.NumberFormatException]
执行protectedMethod()方法
返回值为:11
------------------------

注意:在反射中执行具有可变数量的参数的构造方法时,需要将入口参数定义成二维数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值