Java-反射(Reflect)

Java反射机制允许在运行时动态获取类的信息并调用其方法。相关类包括Class、Constructor、Field和Method等。通过反射,可以创建对象、访问和修改属性、调用任意方法。示例中展示了如何使用反射进行类的实例化、字段访问和方法调用。
摘要由CSDN通过智能技术生成

定义

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

反射机制的相关类

与Java反射相关的类如下:

类名用途
Class类代表类的实体,在运行的Java应用程序中表示类和接口
Field类代表类的成员变量(成员变量也称为类的属性)
Method类代表类的方法
Constructor类代表类的构造方法

示例

//实体类
public class Test {
    private int num;
    public String no;
    protected String str;
    private static  String s = "this is a private static member";
    public Test()
    {
        num = 0;
        no = "The object has been created successfully";
        str = "test";
    }

    public Test(int num, String no, String str)
    {
        this.num = num;
        this.no = no;
        this.str = str;
    }

    private Test(Test test)
    {
        this.num = test.num;
        this.no = test.no;
        this.str = test.str;
    }

    @Override
    public String toString()
    {
        return no + " and the num is " + num;
    }

    public String func1(String str)
    {
        System.out.println("this is a public function");
        return str;
    }

    private void func2()
    {
        System.out.println("this is a private function");
    }

    public static void main(String[] args)
    {
        System.out.println("This is a main function");
    }
}

实体类就是一些简单public private的属性、方法以及无参和带参的构造函数

 

下面是反射的方法测试

我们要使用反射首先需要获得这个类的Class对象,获取方式有三种

* 1、利用Object的getClass()方法获取
* 2、通过静态class属性获取(任何的数据类型都有一个静态的class属性)
* 3、通过Class类的forName()方法获取
* 注:在运行期间一个类只会有一个Class对象生成
        //第一种方式
        Test test = new Test();
        Class testClass = test.getClass();
        System.out.println(testClass.getName());
        //第二种方式
        Class testClass2 = Test.class;
        System.out.println(testClass.equals(testClass2));
        //第三种方式
        try {
            Class testClass3 = Class.forName("Test");
            System.out.println(testClass==testClass3);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
* 注:在运行期间一个类只会有一个Class对象生成,所以在第三种返回的==,结果是true

1、获取、使用构造函数

* 获取构造方法
* 1、getDeclaredConstructors()获取所有的构造方法,包括private和protected
* 2、getConstructors()获取所有的public构造方法
* 3、getConstructor(null)获取无参的public构造方法
* 注:前两种方法都是返回Constructor对象数组,第三种是返回Constructor对象,因为无参构造函数只可能有一种嘛
        Constructor[] constructors = testClass.getDeclaredConstructors();
        //Constructor[] constructors = strClass.getConstructors();
        //Constructor constructor1 = strClass.getConstructor(null);
        for(Constructor constructor : constructors)
        {
            System.out.println(constructor);
        }
* 调用构造函数
* 在这里是无法调用private方法的(会告诉你权限不够IllegalAccessException),这里我就调用无参的构造函数了
* 要想调用需要使用constructor.setAccessible(true)
        Object object = constructors[2].newInstance();
        System.out.println(object);

2、获取成员变量

* 1、getFields()获取所有的public变量
* 2、getDeclaredFields()获取所有的变量
* 3、getField(String name)获取指定名称的变量(只能获取public,若要获取private使用getDeclaredField(String name))
        Field[] fields = testClass.getDeclaredFields();
        for(Field field : fields)
        {
            System.out.println(field);
        }

修改成员变量的值我们可以调用Field类的set方法,如我们修改public成员变量no的值

        Field field = testClass.getField("no");
        field.set(object,"the no has been changed");
        Test test1 = (Test)object;
        System.out.println(test1.no);

如果要修改private成员变量的值也需要先获取权限

        Field field1 = testClass.getDeclaredField("num");
        field1.setAccessible(true);
        field1.set(object,1);
        test1 = (Test)object;
        System.out.println(test1);

3、获取、调用方法(不包括构造函数)

* 1、getMethods()获取所有的public方法
* 2、getDeclaredMethods()获取所有的方法
* 3、getMethod(String name,Class pramaType)获取指定名称的方法,同样的,要获取private要是用getDeclaredMethod
        System.out.println("********************获取所有的方法***********************");
        Method[] methods = testClass.getDeclaredMethods();
        for(Method method : methods)
        {
            System.out.println(method);
        }
        System.out.println("********************调用public方法***********************");
        Method method = testClass.getMethod("func1", String.class);
        method.invoke(object,"test");
        System.out.println("********************调用private方法***********************");
        method = testClass.getDeclaredMethod("func2");
        /**
         * 同样的这里需要提权
         */
        method.setAccessible(true);
        method.invoke(object);
        System.out.println("********************调用main方法***********************");
        method = testClass.getMethod("main", String[].class);
        /**
         * main方法是static的,所以不需要对象也能运行,所以第一个参数可以为null
         * 第二个参数也就是String数组args,但是jdk1.5之后是作为一个可变参数传进去的,所以这里要强制转为Object
         */
        method.invoke(null,(Object) new String[]{});
* 解释一下可变参数
* 像add中的num就是可变参数,它的个数是不确定的,所以可变参数只能放在最后面,要不然程序也无法判断哪些是可变参数
* 特点:
* (1)只能出现在参数列表的最后;
* (2)...位于变量类型和变量名之间,前后有无空格都可以;
* (3)调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
* 适用场景:
*      适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。

例如我写一个累加的函数

    public static int add(int...num)
    {
        int sum = 0;
        for(int i = 0; i < num.length; i++)
        {
            sum+=num[i];
        }
        return sum;
    }

调用就可以这么调用

add(1,2,3);

参数列表的长度是不固定的,只要是int型的就可以

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值