java的反射机制

java的反射机制

反射机制是什么

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

​ 简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。

反射机制能做什么

反射机制主要提供了以下功能:

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;
  • 生成动态代理

反射机制的优点与缺点

为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态编译与静态编译的概念,

  • 静态编译:在编译时确定类型,绑定对象,即通过。
  • 动态编译:运行时确定类型,绑定对象。

动态编译最大限度发挥了java的灵活性,体现了多 态的应用,有效降低类之间的藕合性。

  • 优点:反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在JavaEE的开发中 它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如 这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
  • 缺点:它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。

认识 Class 类

​ Class类的实例表示Java应用运行时的类或接口(每个java类运行时都在JVM里表现为一个Class对象,可通过多种方式来获取Class的对象。数组同样也被映射为为Class 对象的一个类,所有具有相同元素类型都共享该 Class 对象,相同类型数组也共享Class对象。8个基本类型和关键字void同样表现为 Class 对象。

Class 类能做什么

​ 通过Class类我们可以创建该类的实例(对象),可以获取该对象的所有属性信息(修饰符、属性名等)、所有方法信息(修饰符、返回值类型、参数列表等),以及可以获得改类继承的父类、该类实现的接口等信息。甚至可以修改被private修饰的成员属性,可以调用private修饰的成员方法。

获取 Class 对象的方式

// 一般采用这种形式(需要处理异常 ClassNotFoundException )
Class<?> class1 = Class.forName("com.yztc.lin.model.TestReflect");
Class<?> class2 = new TestReflect().getClass();
Class<?> class3 = TestReflect.class;
System.out.println("类名称   " + class1.getName());// getName 获得完整的类名(含包名)
System.out.println("类名称   " + class2.getName());
System.out.println("类名称   " + class3.getName());

Class 常用方法

方法名方法解释
static Class forName(String className)通过完整的类名获得该类的 Class对象
String getName()获得完整的类名(含包名)
Class getSuperclass()取得父类的Class
Class[] getInterfaces()获取所有的实现的接口
T newInstance()通过默认构造器实例化对象
Constructor[] getConstructors()获得该类的所有构造器
Constructor\ getConstructor(Class… parameterTypes)根据参数列表,获得该类的指定构造器
Field[] getDeclaredFields()获得本类的全部属性
Field getDeclaredField(String name)根据名字获取本类属性
Field[] getFields()获得本类及实现的接口或父类的全部public属性
Field getField(String name)根据名字获取接口或父类的public属性
Method[] getDeclaredMethods()获得本类的全部方法
Method getDeclaredMethod(String name, Class… parameterTypes)根据方法名和参数列表获取本类方法
Method[] getMethods()获得实现的接口或父类的全部public方法
Method getMethod(String name, Class… parameterTypes)根据方法名和参数列表获取接口或父类的public方法
int getModifiers();获得Class的访问修饰符类型 返回int值
boolean isInterface();判断Class 是否是接口

反射的使用

获取一个对象的父类与实现的接口

// 取得父类
Class<?> parentClass = class1.getSuperclass();
System.out.println("clazz的父类为:" + parentClass.getName());
// 获取所有的接口
Class<?> intes[] = clazz.getInterfaces();
System.out.println("clazz实现的接口有:");
for (int i = 0; i < intes.length; i++) {
    System.out.println((i + 1) + ":" + intes[i].getName());
}

获取某个类的构造器

获取某个类的具体构造器
Constructor<?> con = class1.getConstructor(int.class, String.class);//传递具体的参数列表的Class
Class<?> clazzs[] = con.getParameterTypes();// 获得该构造器的参数列表
System.out.print("con :");
for (int i = 0; i < clazzs.length; i++)
    System.out.print(clazzs[i].getName() + "\t");
获取某个类的所有public构造器
Constructor<?> cons[] = class1.getConstructors();
    // 查看每个构造方法需要的参数
for (int i = 0; i < cons.length; i++) {
    System.out.print("cons[" + i + "] :");
    Class<?> clazzs[] = cons[i].getParameterTypes();//获得该构造器的参数列表
    for (int j = 0; j < clazzs.length; j++)
        System.out.print(clazzs[j].getName() + "\t");
    System.out.println();
}
通过反射机制实例化一个类的对象
  1. 方式一:通过默认构造器实例化对象

    Class<?> class1 = Class.forName("com.yztc.lin.model.Student");
    Student stu = (Student) class1.newInstance();//默认走空构造器
    stu.setAge(20);
    stu.setName("Rollen");
    System.out.println(user.toString());
  2. 方法二:通过指定构造器实例化对象

    Class<?> class1 = Class.forName("com.yztc.lin.model.Student");
    //Constructor<?> cons[] = class1.getConstructors();
    //Constructor<?> con =cons[1];
    Constructor<?> con = class1.getConstructor(int.class, String.class);//传递具体的参数列表的Class
    Student stu = (Student) con.newInstance(18,"张三");//走两个参数的空构造器
    System.out.println(user.toString());

反射某个类属性信息

Field类 相关方法

方法名方法解释
Field.getModifiers()获取修饰符类型 返回int值
Modifier.toString(int mod)根据修饰符类型 返回具体的修饰符字符串
Field.getType()返回属性的类型
Field.getName()返回属性的名字
void setAccessible(boolean flag)如果访问权限不够,可以设置该属性变成可访问
void set(Object obj, Object value)改变属性的值 set(属性所在的对象,值)
Object get(Object obj)获取属性的值 get(属性所在的对象)
根据属性名获取 本类 的属性
// 取得本类的 age 属性
Field f = clazz.getDeclaredField("age");
//修饰符类型
int mo = f.getModifiers();
String priv = Modifier.toString(mo);
// 属性类型
Class<?> type = f.getType();
System.out.println(priv + " " + type.getName() + " " + f.getName() + ";");
获取本类的全部属性
 // 取得本类的全部属性
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
    Field f = fields[i];
    String s = Modifier.toString(f.getModifiers())+" "+f.getType().getName()+" "+f.getName();
    System.out.println(s);
}
根据属性名获取接口或父类的public属性
// 取得接口或父类的 age 属性
Field f = clazz.getField("name");
String s = Modifier.toString(f.getModifiers())+" "+f.getType().getName()+" "+f.getName();
System.out.println(s);
获取接口或父类的全部public属性
 // 取得本类的全部属性
Field[] fields = clazz.getFields();
for (int i = 0; i < fields.length; i++) {
    Field f = fields[i];
    String s = Modifier.toString(f.getModifiers())+" "+f.getType().getName()+" "+f.getName();
    System.out.println(s);
}
通过反射机制操作某个类的属性
Class<?> clazz = Student.class;
Object obj = clazz.newInstance();
Field field = clazz.getDeclaredField("name");
//field.setAccessible(true);//可以直接对 private 的属性赋值
field.set(obj, "Java反射修改属性值");
System.out.println(field.get(obj));//获取属性的值

获取某个类的全部方法

Method类的 相关方法

方法名方法解释
int getModifiers()获取方法的修饰符类型
Modifier.toString(int mod)根据修饰符类型 返回具体的修饰符字符串
Class getReturnType()获取返回值类型
String getName()获取方法名
Class[] getParameterTypes()获取参数列表
根据方法名和参数列表获取 本类 的方法
Method method = class1.getDeclaredMethod("privateMethod", String.class, int.class);
int modifiers = method.getModifiers();//得到修饰符类型 返回int值
String modifierStr = Modifier.toString(modifiers);//根据修饰符类型 返回具体的修饰符字符串
Class<?> returnType = method.getReturnType();//得到返回值类型
String methodName = method.getName();//得到方法名
System.out.print(modifierStr+" "+returnType+" "+methodName+" (");
Class<?>[] parameterTypes = method.getParameterTypes();// 得到方法的参数列表是
for (int i = 0; i < parameterTypes.length; i++) {
    Class<?> c = parameterTypes[i];
    if (i==parameterTypes.length-1) {
        System.out.print(c.getName()+" arg"+i);
        break;
    }
    System.out.print(c.getName()+" arg"+i+",");
}
System.out.println(")");
获取本类的全部方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
    System.out.print(Modifier.toString(method.getModifiers()) + " " + method.getReturnType() + " " + method.getName() + " (");
     Class<?>[] parameterTypes = method.getParameterTypes();// 得到方法的参数列表是
    for (int i = 0; i < parameterTypes.length; i++) {
        Class<?> c = parameterTypes[i];
        if (i == parameterTypes.length - 1) {
            System.out.print(c.getName() + " arg" + i );
            break;
        }
        System.out.print(c.getName() + " arg" + i + ",");
    }
    System.out.println(")");
}
根据方法名和参数列表获取接口和父类的public方法
    Method method = class1.getMethod("publicMethod", String.class, int.class);
    System.out.print(Modifier.toString(method.getModifiers()) + " " + method.getReturnType() + " " +method.getName() + " (");
    Class<?>[] parameterTypes = method.getParameterTypes();// 得到方法的参数列表是
    for (int i = 0; i < parameterTypes.length; i++) {
        Class<?> c = parameterTypes[i];
        if (i == parameterTypes.length - 1) {
            System.out.print(c.getName() + " arg" + i );
        break;
        }
        System.out.print(c.getName() + " arg" + i + ",");
    }
    System.out.println(")");
获取接口和父类的全部public方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
    System.out.print(Modifier.toString(method.getModifiers()) + " " + method.getReturnType() + " " + method.getName() + " (");
    Class<?>[] parameterTypes = method.getParameterTypes();// 得到方法的参数列表是
    for (int i = 0; i < parameterTypes.length; i++) {
        Class<?> c = parameterTypes[i];
        if (i == parameterTypes.length - 1) {
            System.out.print(c.getName() + " arg" + i );
            break;
        }
        System.out.print(c.getName() + " arg" + i + ",");
    }
    System.out.println(")");
}
通过反射机制调用某个类的方法
public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("com.yztc.lin.model.Test");
        Object obj = clazz.newInstance();
        /** 调用Test类中的 test1 方法**/
        Method method = clazz.getDeclaredMethod("test1");
        //method.setAccessible(true);//打破访问权限的范围限制
        Object returnVal = method.invoke(obj);
        System.out.println("得到返回值:"+returnVal);

        /**调用Test的test1方法**/
        method = clazz.getMethod("test2", int.class, String.class);
        method.invoke(obj, 20, "张三");
    }

    private int test1() {
        System.out.println("通过反射调用了方法1");
        return 123;
    }

    public void test2(int i, String s) {
        System.out.println("通过反射调用了方法2 i:" + i + " s:" + s);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值