Java 反射学习

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

    ·Java反射机制主要提供了以下功能:在运行时判定任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判定任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

    反射的应用场景:
     · 逆向代码 ,例如反编译
     · 与注解相结合的框架 例如spring
     · 单纯的反射机制应用框架
     · 动态生成类框架
    反射机制的优缺点:
     优点:
      运行期类型的判断,动态类加载,动态代理使用反射。
     缺点:
      性能是一个问题,反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码

在学习之前有必要知道类加载器和实例对象(Class和newInstance)的区别:
·这篇文章写的蛮不错的 https://blog.csdn.net/championhengyi/article/details/78778575

示例下载地址: https://github.com/Hairo1/java-Reflect.git

1.通过反射创建对象
反射无参构造方法创建实例

 Class<?> clazz = Class.forName("类路径");//如:com.xx.xxx.类名
            Object o = clazz.newInstance();
            System.out.println("通过无参构造方法反射实例化:"+o.toString());

反射带参构造方法创建实例

   Class<?>   clazz = Class.forName(calssPathName);
            //获取String类型参数的构造方法
            Constructor<?> constructor = clazz.getConstructor(String.class);
            //反射实例化带String类型参数的构造方法
            Object o = constructor.newInstance("Hairo");
            System.out.println("通过带参构造方法反射实例化:"+o);

2.通过反射给成员变量赋值

   Class clazz = Class.forName(this.classPathName);
            //创建类实例
            Object o =  clazz.newInstance();
            //获取指定属性名进行赋值  getField(name);--不能获取私有的属性
            Field field = clazz.getDeclaredField("name");
            //因为属性私有的所以必须开启权限才能操作
            field.setAccessible(true);
            //指定属性名赋值 k-v
            field.set(o, "反射设置私有name属性的值");
            //调用输出方法-输出null为赋值失败
            //指定方法名获取show方法
            Method method =clazz.getMethod("show");
            //调用show方法 o代表那个对象的show方法,
            method.invoke(o);

3.反射获取方法并调用

 Class<?> clazz = Class.forName(classPathName);
            Object o = clazz.newInstance();
            //获取所有方法并执行
            Method[] methods = clazz.getDeclaredMethods();
            //获取所有实例方法
            for (Method method : methods){
                //method.getTypeParameters();获取方法的参数列表---懒得写了
                System.out.println("执行方法:"+method);
                //开启权限去执行方法
                method.setAccessible(true);
                //方法参数为0个的时候执行
                if(method.getTypeParameters().length==0){
                    method.invoke(o);
                    System.out.println("");
                }
            }

4.反射获取注解
注解都是自定义的
01.获取类上运行期间有效的注解

 Class clazz = Class.forName(classPathName);
            //获取类上的所有运行期间有效的注解
            Annotation[] annotations = clazz.getAnnotations();
            for (Annotation annotation : annotations){
                System.out.println(classPathName+"类存在注解:"+annotation);
                //判断类上是否存在某个注解
                System.out.println("是否存在@Service注解:"+clazz.isAnnotationPresent(Service.class));
                if(clazz.isAnnotationPresent(Service.class)){
                    //转换为该注解的类型
                    Service service = (Service) annotation;
                    //获取注解@Service  name设置的值
                    System.out.println("@Service的name值:"+service.name());
                    //获取注解@Service  value设置的值
                    System.out.println("@Service的value值:"+service.value());
                }
            }

02.获取属性上的注解

 Class clazz = Class.forName(classPathName);
            //获取所有属性,包括private修饰的属性
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields){

                //System.out.println(field.getAnnotation(Resource.class));
                //判断属性是否存在@Resource
                if(field.isAnnotationPresent(Resource.class)){
                    Resource resource = field.getAnnotation(Resource.class);
                    System.out.println(resource.name());
                    System.out.println(resource.value());
                    //这里就可以实现如何按指定名称/类名小写开头/类型。。。注入
                    //@service 没有指定
                    if(resource.name().equals("default")){
                        //默认按类型或者按类名小写开头注入
                     }else{
                        //@service("xxxx");
                        //默认按指定名称注入。。。。。
                    }

                }else{
                    //判断其他注解如:@Autowired主动注入
                }
            }

03.获取方法上的注解

 Class clazz = Class.forName(classPathName);
            //获取所有方法,包括private修饰的方法
            Method[] methods = clazz.getDeclaredMethods();
            for(Method method : methods){
                System.out.println(method+"方法的注解"+method.getAnnotation(com.hairo.annotations.Method.class));
            }

示例下载地址: https://github.com/Hairo1/java-Reflect.git

反射的其他Api,示例已经实现了大部分:
/**
*其他的api
* Calss<?>[] getClasses()
* 返回一个数组,其中包含 类对象代表所有的公共类和接口这个 类对象所表示的类的成员。
* Class<?>[] getInterfaces()
* 决定了接口由这个对象所表示的类或接口实现。
*int getModifiers()
* 返回Java语言修饰符的类或接口,编码在一个整数。
* String getName()
* 返回的实体的名称(数组类,接口,类、原始类型或空白)由这个 类对象,作为 String。
* Package getPackage()
* 这个类的包。
* ProtectionDomain getProtectionDomain()
* 返回该类的 ProtectionDomain。
* URL getResource(String name)
* 发现与一个给定名称的资源。
* InputStream getResourceAsStream(String name)
* 发现与一个给定名称的资源。
* Object[] getSigners()
* 这个类的签名者。
* String getSimpleName()
* 返回底层类的简单的名称在源代码中给出。
* Class<? super T> getSuperclass()
* 返回 类代表实体的超类(类,接口,原始类型或空白)由这 类表示。
* String getTypeName()
* 返回一个字符串信息为这种类型的名称。
* TypeVariable<类>[] getTypeParameters()
* TypeVariable对象返回一个数组表示泛型声明的变量类型声明由这个 GenericDeclaration对象,按声明顺序。
* boolean isAnnotation()
* 返回true,如果这 类对象代表一个注释类型。
* boolean isAnnotationPresent(类<? extends Annotation> annotationClass)
* 返回true,如果指定类型的注释出现在这个元素,其他的错误的。
* boolean isAnonymousClass()
* 返回 true当且仅当底层类是一个匿名类。
* boolean isArray()
* 决定如果这 类对象表示一个数组类。
* boolean isAssignableFrom(类<?> cls)
* 确定这个 类对象所表示的类或接口是一样的,或者是一个超类或超接口,所表示的类或接口指定 类参数。
* boolean isEnum()
* 返回true当且仅当这个类声明为enum的源代码。
* boolean isInstance(Object obj)
* 确定指定的 Object型态与对象由这 类表示。
* boolean isInterface()
* 确定指定的 类对象表示一个接口类型。
* boolean isLocalClass()
* 返回 true当且仅当底层类是当地的一个类。
* boolean isMemberClass()
* 返回 true当且仅当底层类是一个类成员。
* boolean isPrimitive()
* 确定如果指定的 类对象代表一个原始类型。
* boolean isSynthetic()
* 返回 true如果这类是一个合成类;否则返回 false
* T newInstance()
* 创建一个新的这个 类对象所表示的类的实例。
* String toGenericString()
* 返回一个字符串描述这个 类,包括修饰符和类型参数信息。
* String toString()
* 将对象转换为一个字符串。
*
*/
示例下载地址: https://github.com/Hairo1/java-Reflect.git

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值