今天看看Java反射

什么是Java反射

Java反射机制是在运行状态中,对于任何一个类,都能知道这个类的属性和方法, 对于任何一个对象,都能够调用它的任意一个方法和属性。

Java反射主要是用来

  1. 在运行时判断任意一个对象所属的类。
  2. 在运行时构造任意一个类的对象。
  3. 在运行时判断任意一个类所具有的成员变量和方法。
  4. 在运行时调用任意一个对象的方法,生成动态代理。

反射的三种方式

  1. 通过 Class.forName() 方法加载字符串,就可以得到该字符串做代表的Class对象
Class<?> cls = Class.forName("com.java.Demo");
  1. 通过类名调用class属性得到该类的Class对象。
Class<?> cls = Demo.class;
  1. 通过实例的 getClass() 方法得到Class对象
Demo demo = new Demo();
Class <?> cls = demo.getClass();

这三种方法,最后都是要得到一个Class对象,然后获取字段和函数的的方法,都是围绕着这个Class对象来实现的。

生成对象

  1. 先获得Class对象,然后通过该Class对象的newInstance()方法获取对象。
Class<?> classType = String.class;

Object obj = classType.newInstance();
  1. 先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成
Class<?> classType = Customer.class;

// 获得Constructor对象,此处获取第一个无参数的构造方法的
Constructor cons = classType.getConstructor(new Class[] {});

// 通过构造方法来生成一个对象
Object obj = cons.newInstance(new Object[] {});

但是,上面这种情况只适用于默认的 无参构造函数 ,但是如果是有参构造函数,则会报错。

Exception in thread "main" java.lang.InstantiationException: com.gzl.demo.InvokeTest
    at java.lang.Class.newInstance(Class.java:418)
    at com.gzl.demo.InvokeTest.main(InvokeTest.java:33)
Caused by: java.lang.NoSuchMethodException: com.gzl.demo.InvokeTest.<init>()
    at java.lang.Class.getConstructor0(Class.java:2971)
    at java.lang.Class.newInstance(Class.java:403)
    ... 1 more

这个时候,可以用下面的方法:

Class<?> classType = InvokeTest.class;
//getConstructor(Class<?>... parameterTypes),传递的是可变Class参数
Constructor cons2 = classType.getConstructor(new Class[] {String.class, int.class});
//当是基本数据类型传入的时候,需要一个包装类来包装它,但是jdk1.5也可以直接传入基本数据类型了,因为编译器会帮你自动装箱,拆箱
Object obj2 = cons2.newInstance(new Object[] {"ZhangSan",20});

两种不同的方法的区别

通过反射创建新的类示例,有两种方式:
Class.newInstance()
Constructor.newInstance()

以下对两种调用方式给以比较说明:
Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数;

Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数。

Class.newInstance() 抛出所有由被调用构造函数抛出的异常。

Class.newInstance() 要求被调用的构造函数是可见的,也即必须是public类型的;

Constructor.newInstance() 在特定的情况下,可以调用私有的构造函数。

获取函数Method

一行代码获取所有的方法。

Method[] methods = clazz.getDeclaredMethods();

可以看看Method的API
大概就是几个Get方法,常用的包括:

  1. getModifiers()
    以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符。

  2. getName()
    以 String 形式返回此 Method 对象表示的方法名称。

  3. getReturnType()
    返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型。

  4. invoke(Object obj, Object… args)

    对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
    在使用invoke方法之前可以先用

    class.getMethod(String name,Class

getxxx(field,method,constructor)和getDeclaredxxx(field,method,constructor)的区别

  • getxxx() 只能访问类中的私有字段,而共有的字段是无法访问的,能访问从其他类继承下来的公共方法。

返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。返回数组中的元素没有排序,也没有任何特定的顺序。

如果类或接口没有可访问的公共字段,或者表示一个数组类、一个基本类型或 void,则此方法返回长度为 0 的数组。

特别地,如果该 Class对象表示一个类,则此方法返回该类及其所有超类的公共字段。
如果该 Class 对象表示一个接口,则此方法返回该接口及其所有超接口的公共字段。
该方法不反映数组类的隐式长度字段。用户代码应使用 Array 类的方法来操作数组。

  • getDeclaredxxx()

返回一个构造函数对象数组,反映由这个类对象所表示的类所声明的所有构造函数。

这些都是public、protected、default和private。返回的数组中的元素没有排序。

如果类有一个默认的构造函数,它被包含在返回的数组中。如果这个类对象表示一个接口,一个原始类型,一个数组类,或void,此方法返回一个长度为0的数组。

一个例子获取所有需要的方法

记得新建一个类,然后改一下forName()里面包的路径。

package com.gzl.demo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test {


    public static void main(String[] args){
        try {
               //获取Student的Class对象
               Class<?> clazz = Class.forName("com.gzl.demo.Student");
               //获取该类中所有的属性
               Field[] fields = clazz.getDeclaredFields();
               System.out.println("下面打印类中所有属性");
               //遍历所有的属性
               for (Field field : fields) {
                   field.setAccessible(true);

                //打印属性信息,包括访问控制修饰符,类型及属性名
                System.out.println("    修饰符:" + Modifier.toString(field.getModifiers()));
                System.out.println("    类型:" + field.getType().toString());
                System.out.println("    属性名:" + field.getName());
                System.out.println();
               }
               //获取该类中的所有方法
               Method[] methods = clazz.getDeclaredMethods();

               for (Method method : methods) {
                System.out.println("    修饰符:" + Modifier.toString(method.getModifiers()));
                System.out.println("    方法名:" + method.getName());
                System.out.println("    返回类型:" + method.getReturnType());

                //获取方法的参数对象
                Class<?>[] clazzes = method.getParameterTypes();
                for (Class<?> class1 : clazzes) {
                 System.out.println("    参数类型:" + class1);
                 System.out.println();
                }
               }

              } catch (Exception e) {
               e.printStackTrace();
              }
             }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值