2020-12-09

太懒了之前写了几篇就不想写了,慢慢更吧

反射的作用介绍略过。。。。。。。

获得类

             // 运行时 Class.forName 根据全类名(全路径加类名) 动态获取类
             Class aClass  = Class.forName("Reflection.model.UserBean");
             // 获取实例
             UserBean  userBean = (UserBean) aClass.newInstance() ;
             System.out.println("动态实例 user 全路径类名 "+ aClass.getName() );
             System.out.println("动态实例 user 类名  " +   aClass.getSimpleName());

获得类修饰符

             //modifiers
             /** PUBLIC: 1
             PRIVATE: 2
             PROTECTED: 4
             STATIC: 8
             FINAL: 16
             SYNCHRONIZED: 32
             VOLATILE: 64
             TRANSIENT: 128
             NATIVE: 256
             INTERFACE: 512
             ABSTRACT: 1024
             STRICT: 2048**/
             //getModifiers() 获得的是修饰符对应的数字
             int modifiers  =  aClass.getModifiers() ;
             System.out.println( "类的修饰符" + modifiers );
             Package aPackage =aClass.getPackage();
             System.out.println("获取类的package info  " + aPackage.getName() );

  获得方法

             //获得对象里方法 并分别打印 get set 方法名称
             // invoke 动态修改对象
             Method [] methods  = aClass.getMethods();
             for (Method method : methods) {
                  if(isSetter(method)) {
                      // 检测到setname 方法 invoke动态setname 
                      if(method.getName().equals("setName") ){
                          method.invoke(userBean,"zhangsan");
                          // invoke(obj 目标类的实例 ,args // 传入参数)
                      }
                      System.out.println("Setter   " + method.getName());
                  }
                 if(isGetter(method)) {
                     System.out.println("Getter   "+ method.getName());
                 }
             }



       public static boolean isGetter(Method method){
        if(!method.getName().startsWith("get"))      return false;
        if(method.getParameterTypes().length != 0)   return false;
        if(void.class.equals(method.getReturnType()))return false;
        return true;
        }

       public static boolean isSetter(Method method){
        if(!method.getName().startsWith("set"))    return false;
        if(method.getParameterTypes().length != 1) return false;
        return true;
       }

 获得字段

             // getDeclaredField 私有字段与方法
             privateBean   privatebean  = new privateBean("defaultvalue");
             Class  pbclazz = Class.forName("Reflection.model.privateBean");
             Field privateFiled = privatebean.getClass().getDeclaredField("stringdefaultvalue");
             /* 将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
             值为 false 则指示反射的对象应该实施 Java 语言访问检查;实际上setAccessible是启用和禁用访问安全检查的开关,
             并不是为true就能访问为false就不能访问 ;https://blog.csdn.net/buyaoshuohua1/article/details/104175188
             由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的*/
             privateFiled.setAccessible(true);
             String fieldValue  = (String) privateFiled.get(privatebean);
             System.out.println("filedValue = " + fieldValue);
             //获取私有字段数组
             Field []  fields = privatebean.getClass().getDeclaredFields();
             for (int i = 0; i < fields.length; i++) {
                 fields[i].setAccessible(true);
                 // 注意调用  pbclazz.newInstance() 调用的是无参构造方法
                 // 使用有参构造需要使用 getDeclaredConstructor 先获取对应参数的有参构造方 
                  法才能Instance 使用
                 Object  name = 
   fields[i].get(pbclazz.getDeclaredConstructor(String.class).newInstance("defaultvalue"));
                 System.out.println("stringdefaultvalue : " + name );
             }

 获取字段时注意方法区别

/*
* getFields()与getDeclaredFields()区别:getFields()只能访问类中声明为公有的字段,私有的字段它无法访问,
* 能访问从其它类继承来的公有方法.getDeclaredFields()能访问类中所有的字段,与public,private,protect无关,
* 不能访问从其它类继承来的方法
* getMethods()与getDeclaredMethods()区别:getMethods()只能访问类中声明为公有的方法,
* 私有的方法它无法访问,能访问从其它类继承来的公有方法.getDeclaredFields()能访问类中所有的字段,
* 与public,private,protect无关,不能访问从其它类继承来的方法
* getConstructors()与getDeclaredConstructors()区别:getConstructors()只能访问类中声明为public的构造函数.
* getDeclaredConstructors()能访问类中所有的构造函数,与public,private,protect无关
* */

泛型反射 修改泛型类型

 // The Generics Reflection Rule of Thumb   泛型反射法则
 // 获得 泛型返回类型 List<String>   class java.lang.String
 Method  method  =  MySt.class.getMethod("getStringList",null); // 反射获得方法
 Type returnType =  method.getGenericReturnType();// 此Method对象表示的方法的正式返回类型
               / *List< ? extends BaseBean> list = new ArrayList<>();
                list.get(1);*/
                Type  newtype = Long.class;
                Type  oldtype = java.lang.String.class;
                if(returnType instanceof ParameterizedType){
 //Method  method  =  MySt.class.getMethod("getStringList",null); // 反射获得方法
Type returnType =  method.getGenericReturnType();// 此Method对象表示的方法的正式返回类型
                 // returnType 是自己去主动获得的 ??
// ParameterizedType 是怎么获得或者说找到这个returnType的来源的method对象的泛型呢??
                 // ParameterizedType 参数化类型
                 ParameterizedType  type = (ParameterizedType) returnType;
                 Type []  typeArguments  = type.getActualTypeArguments();
                 for(Type typeArgument : typeArguments) {
                      Class typeArgClass = (Class) typeArgument;
                      System.out.println("修改前type  = " + typeArgClass);
                 }
                  //利用ParameterizedType实现type修改
                 for (int i = 0; i < typeArguments.length; ++i) {
                     if(typeArguments[i] == oldtype){
                         System.out.println("替换type String  -->  Long");
                         typeArguments[i] = newtype;
                     }
                 }
                 for(Type typeArgument : typeArguments) {
                     Class typeArgClass = (Class) typeArgument;
                     System.out.println("修改后 type = " + typeArgClass);
                 }
             }

  看到泛型反射我就想到5月份找工作碰到的面试题,现在还记忆犹新

   /*
    List<? extend String>
    当初的问题
    虽然有了解答其实还是半知半解
    https://tieba.baidu.com/p/6711807461
    */
    public static void main(String[] args) {
        //上界
        List<? extends Fruit> flistTop = new ArrayList<Apple>();
        flistTop.add(null);
        //add Fruit对象会报错
        //flistTop.add(new Fruit());
        Fruit fruit1 = flistTop.get(0);
        //下界
        List<? super Apple> flistBottem = new ArrayList<Apple>();
        // flistBottem.add(new Fruit()); 不能add apple 的父类  只能add apple及其子类
        flistBottem.add(new Apple());
        flistBottem.add(new Jonathan());
        //get Apple对象会报错
        //Apple apple = flistBottem.get(0);
        /*
        *   记住泛型只能向上转型
        *   ? extend Fruit 泛型上界    ? extend ,只能作为生产者
        *  表示泛型 fruit类 和所有继承fruit类的子类
        *  这种泛型 可以从容器中取出东西 但是却不能放东西
        *  因为当你取出东西时 不论什么情况 都能知道 这个容器中放的必定是一个fruit
        *  因此当取出时未知的子类时都可以向上转型为fruit承接
        *  但是当你放入一个子类时虽然知道放入的一个水果,但是不知道具体到底是什么
        *  在容器里找不到对应的类承接 , ( 泛型类型擦除 ?? )
        *  拓展java泛型实现
        * (Java中的泛型基本上都是在编译器这个层次来实现的。
        * 在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。)
        * example ? super    只能作为消费者
        * List<Integer> l1 = new ArrayList<Integer>()
        * List<String>  l2 = new ArrayList<String>()
        * System.out.println(l1.getClass() == l2.getClass()); // true
        * 这是因为在实际编译过程中 Integer 和 String已经被擦出 所以 l1 l2 getClass() 都是 list.class
        *   ? extend base   ? 泛型占位符
        *   ? super Apple  泛型下界
        *  表示泛型 以Apple 为下类以及Apple的所有父类 一直可追溯到 Object 类
        *  可以放东西却不能取出东西
        *  你不能add Apple的父类,因为不能确定List里面存放的到底是哪个父类。
        *  但是可以add Apple及其子类。因为不管我的子类是什么类型,它都可以向上转型为Apple及其所有的
        *  父类甚至转型为Object 用来承接 ,但是当我get的时候,Apple的父类这么多,我用什么接着呢,除了Object,
        *  其他的都接不住。所以,归根结底可以用一句话表示,那就是编译器可以支持向上转型
        * */

   最后用反射搞一个注解

    自定义一个注解类

/*元注解:

  元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
    1.@Target,
    2.@Retention,
    3.@Documented,
    4.@Inherited
  这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。

  @Target:

   @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

  作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

  取值(ElementType)有:

    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明*/
// https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
     //可以什么都不定义 
    public String name(); 
    public String value();
}

  OK  当初学注解天真以为只要定义万就可以了,不过确实也没有问题,但是想要注解真正的生效达到想要的功能肯还需要对应的实现

  注解功能实现

 

public class MyAnnotationimpl {
    public    void myanno() throws ClassNotFoundException {
        ClassLoader cl = this.getClass().getClassLoader();
        Class  clazz  = cl.loadClass("Reflection.Annotation.AnnotationTest");//注解类路径

        Annotation [] annotations =  clazz.getAnnotations();
       try {
           for (Annotation annotation : annotations) {
               if (clazz.isAnnotationPresent(MyAnnotation.class)) {
                   MyAnnotation myAnnotation = (MyAnnotation) annotation;
                   System.out.println("name : " + myAnnotation.name());
                   System.out.println("value :" + myAnnotation.value());
                   Method[] methods = clazz.getMethods();
                   AnnotationTest annotationTest = (AnnotationTest) clazz.newInstance();
                   for (Method method : methods
                   ) {
                       if (method.getName().contains("setAnnotationname")) {
                           method.invoke(annotationTest, "动态修改name");
                       }
                       if(method.getName().contains("setAnnotationdes")){
                           method.invoke(annotationTest,"动态描述");
                       }
                       if(method.getName().contains("setAnnotationvalue")){
                           method.invoke(annotationTest,"18");
                       }
                   }
                   System.out.println(annotationTest.toString());
               }
           }
       }catch (Exception e){
           e.printStackTrace();
       }
    }

}

 注解类

@MyAnnotation(name= "zhangsan",value = "18")
public class AnnotationTest {
    private  String  annotationname;
    private  String  annotationdes;
    private  String  annotationvalue;
   //get set ....
}   

 测试注解功能

AnnotationTest annotationTest = new AnnotationTest();
MyAnnotationimpl myAnnotationimpl = new MyAnnotationimpl();
myAnnotationimpl.myanno();

代码

https://share.weiyun.com/13qDdAE6

 

 

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值