Java反射

Java反射

定义

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

反射应该是 JVM读取相应类的字节码文件,而不是.java

性能问题

反射的性能很慢,和直接调用方法相比慢了30倍
如果关闭安全检查(setAccessible(true))也会慢5倍左右

简单地说

  1. Java 反射,就是在运行状态中。
  2. 获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
  3. 获取任意对象的属性,并且能改变对象的属性
  4. 调用任意对象的方法
  5. 判断任意一个对象所属的类
  6. 实例化任意一个类的对象

反射机制的相关类

与Java反射相关的类如下:

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

Class类

Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。

获得类相关的方法

方法用途
asSubclass(Class clazz)把传递的类的对象转换成代表其子类的对象
Cast把对象转换成代表类或是接口的对象
getClassLoader()获得类的加载器
getClasses()返回一个数组,数组中包含该类中所有公共类和接口类的对象
getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象
forName(String className)根据类名返回类的对象
getName()获得类的完整路径名字
newInstance()创建类的实例
getPackage()获得类的包
getSimpleName()获得类的名字
getSuperclass()获得当前类继承的父类的名字
getInterfaces()获得当前类实现的类或是接口
String path="reflection.bean.User";
/**
*User类中包含id,username和password属性
*/
        Class clazz=Class.forName(path);
        //获取全类名
        System.out.println(clazz.getName());
        //获取类名
        System.out.println(clazz.getSimpleName());

结果

reflection.bean.User
User

获得类中属性相关的方法

方法用途
getField(String name)获得某个公有的属性对象
getFields()获得所有公有的属性对象
getDeclaredField(String name)获得某个属性对象
getDeclaredFields()获得所有属性对象

获得类中注解相关的方法

方法用途
getAnnotation(Class annotationClass)返回该类中与参数类型匹配的公有注解对象
getAnnotations()返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass)返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations()返回该类所有的注解对象
/**
         * 获取属性
         */
        Field[] clazzs=clazz.getFields();
        //只能获得public的,否则里面为空
        System.out.println(clazzs.length);
        //获取private的可以
        clazzs=clazz.getDeclaredFields();
        System.out.println(clazzs.length);
        //获取单个属性
        Field f=clazz.getDeclaredField("username");
        System.out.println("获取单个属性"+f);
        for (Field field : clazzs) {
            System.out.println("属性"+field);
        }

结果

获取单个属性private java.lang.String reflection.bean.User.username
属性private int reflection.bean.User.id
属性private java.lang.String reflection.bean.User.username
属性private java.lang.String reflection.bean.User.password

获得类中构造器相关的方法

方法用途
getConstructor(Class…<?> parameterTypes)获得该类中与参数类型匹配的公有构造方法
getConstructors()获得该类的所有公有构造方法
getDeclaredConstructor(Class…<?> parameterTypes)获得该类中与参数类型匹配的构造方法
getDeclaredConstructors()获得该类所有构造方法
/**
         * 构造器(和属性、方法差不多)
         * 有参数时加上参数的class,无参数则填入null
          */
        Constructor[] constructors=clazz.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("构造器"+constructor);
        }

结果

构造器public reflection.bean.User(int,java.lang.String,java.lang.String)
构造器public reflection.bean.User()

获得类中方法相关的方法

方法用途
getMethod(String name, Class…<?> parameterTypes)获得该类某个公有的方法
getMethods()获得该类所有公有的方法
getDeclaredMethod(String name, Class…<?> parameterTypes)获得该类某个方法
getDeclaredMethods()获得该类所有方法
/**
         * 获取方法(和Field一样方法,只不过替换一下单词)
         */
        Method[] methods=clazz.getDeclaredMethods();
        System.out.println("获取所有method方法");
        for (Method method : methods) {
            System.out.println("方法"+method);
        }
        //获取单个方法,无参数则只写方法名和null,有参数要添加参数的class
        Method m1=clazz.getDeclaredMethod("getUsername",null);
        /**
         * 因为java中可以重载同名不同参的方法,为了确定对应的方法,应该选择性的添加参数的class
         */
        Method m2=clazz.getDeclaredMethod("setUsername", String.class);
        System.out.println("m1=>"+m1+"\nm2=>"+m2);

结果

获取所有method方法
方法public java.lang.String reflection.bean.User.toString()
方法public int reflection.bean.User.getId()
方法public java.lang.String reflection.bean.User.getUsername()
方法public void reflection.bean.User.setUsername(java.lang.String)
方法public void reflection.bean.User.setPassword(java.lang.String)
方法public void reflection.bean.User.setId(int)
方法public java.lang.String reflection.bean.User.getPassword()
m1=>public java.lang.String reflection.bean.User.getUsername()
m2=>public void reflection.bean.User.setUsername(java.lang.String)

类中其他重要的方法

方法用途
isAnnotation()如果是注解类型则返回true
isAnnotationPresent(Class<? extends Annotation> annotationClass)如果是指定类型注解类型则返回true
isAnonymousClass()如果是匿名类则返回true
isArray()如果是一个数组类则返回true
isEnum()如果是枚举类则返回true
isInstance(Object obj)如果obj是该类的实例则返回true
isInterface()如果是接口类则返回true
isLocalClass()如果是局部类则返回true
isMemberClass()如果是内部类则返回true

Field类

Field代表类的成员变量(成员变量也称为类的属性)

方法用途
equals(Object obj)属性与obj相等则返回true
get(Object obj)获得obj中对应的属性值
set(Object obj, Object value)设置obj中对应属性值
/**
         * 通过反射API调用属性
          */
        Field field=clazz.getDeclaredField("password");
        //告诉程序field不用作安全检查了(即可访问到private属性进行修改)
        field.setAccessible(true);
        field.set(user,"Field");
        System.out.println("field修改的password=>"+field.get(user));

结果

field中Field

Method类

Method代表类的方法

方法用途
invoke(Object obj, Object… args)传递object对象及参数调用该对象对应的方法
//反射API调用方法
        Method methodSet=clazz.getDeclaredMethod("setUsername", String.class);
        //前者表示对象,后者表示参数(可以不写)
        methodSet.invoke(user,"啦啦啦");
        Method methodGet=clazz.getDeclaredMethod("getUsername");
        System.out.println("通过反射set和get到username是"+methodGet.invoke(user));

结果

通过反射set和get到username是啦啦啦

Constructor类

Constructor代表类的构造方法

方法用途
newInstance(Object… initargs)根据传递的参数创建类的对象
/**
         * 通过反射API调用构造方法、构造对象
         * Class clazz= Class.forName(path);   如果不强转(User)的话,需要改为Class<User> clazz=(Class<User>) Class.forName(path)
         * User user=(User) clazz.newInstance();
         */
        //实际上默认调用了无参构造器方法,所以平时写javabean时最好添加上无参构造器
        User user= (User) clazz.newInstance();
        System.out.println(user);
        Constructor constructor=clazz.getDeclaredConstructor(int.class,String.class,String.class);
        User u1= (User) constructor.newInstance(1,"if","123");
        System.out.println("u1->"+u1);

结果

构造器public reflection.bean.User(int,java.lang.String,java.lang.String)
构造器public reflection.bean.User()
User{id=0, username=‘null’, password=‘null’}
u1->User{id=1, username=‘if’, password=‘123’}

既然反射可以拿到private里的值,那private的意义在哪里?

  1. Java的private修饰符不是为了绝对安全设计的,而是对用户常规使用Java的一种约束。就好比饭店厨房门口挂着“闲人免进”的牌子,但是你还是能够通过其他方法进去。
  2. private的意义是OOP(面向对象编程)的封装概念。
  3. setAccessible(true),这行代码取消了java的权限控制检查,会产生安全隐患

总结

获取Class类的对象:forName()、类名.Class、对象.getClass()
源代码阶段[forName()]–>Class对象阶段(内存)[类名.Class]–>Runtime阶段[对象.getClass()]
.java文件–编译–>Class文件–类加载器–>Class对象–创建对象–>new JavaBean()
要的一些类及其方法,更多信息和用法需要近一步的阅读Google提供的相关文档和示例。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值