zoukankan      html  css  js  c++  java
  • 注解和反射

    注解

    Annotation 是从JDK5.0开始引入的技术。

    内置注解(在java.lang包中)

    • @Override,方法重写。
    • @Deprecated(已被淘汰),可用于修饰类、属性、方法。不推荐程序员使用这样的元素,因为它很危险或者已经存在更好的选择。
    • @SuppressWarnings:抑制编译时的警告信息,需要添加参数才能正常使用。比如:@SuppressWarnings("all")

    元注解

    负责注解其他注解,java定义了4个标准的meta-annotation类型。

    • @Target,描述注解的使用范围
    • @Retention,描述注解的生命周期
      • SOURCE < CLASS < RUNTIME
    • @Document,表示该注解将被包含在 javadoc中
    • Inherited,说明子类可以继承父类中的该注解

    自定义注解

    @interface + 注解名{ 参数类型 + 参数名(); }

    @Target({ElementType.TYPE,ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface DIY {
        String name() default "";
        int age();
    }
    

    反射机制(Java.Reflection)

    反射机制允许程序在运行期间,借助反射API获取任何类的内部信息,并且能直接操作任意对象的内部属性及方法。

    Class c = Class.forName("java.lang.String");

    类加载完之后,在堆内存的方法区中就产生了一个Class类对象(Class类是用来描述类的类,一个类只有一个Class类对象),这个Class类对象包含了完整的类的结构信息。

    反射的功能

    • 运行时判断任意一个对象所属的类
    • 运行时判断任意一个类所具有的属性和方法
    • 运行时构造任意一个类的对象
    • 运行时获取泛型信息
    • 运行时调用任意一个对象的属性和方法
    • 运行时处理注解
    • 生成动态代理

    反射优点:

    • 可以动态创建对象,灵活性很强

    缺:

    • 对性能有影响,执行速度比较慢

    反射相关的主要API

    API Description
    java.lang.Class 代表一个类
    java.lang.reflect.Method 代表类的方法
    java.lang.reflect.Field 代表类的属性
    java.lang.reflect.Constructor 代表类的构造器

    获取Class对象的方式

            //1.通过全限定类名获得
            Class<?> c1 = Class.forName("reflect.User");
            //2.通过对象获得
            Class c2 = new User().getClass();
            //3.通过类名.class获得
            Class c3 = User.class;
    

    所有类型的class

    //      所有类型的class:
            Class<Object> objectClass = Object.class;
            Class<Comparable> comparableClass = Comparable.class;//接口
            Class<String[]> aClass = String[].class;
            Class<String[][]> aClass1 = String[][].class;
            Class<Override> overrideClass = Override.class;//注解
            Class<ElementType> elementTypeClass = ElementType.class;//枚举
            Class<Integer> integerClass = Integer.class;
            Class<Void> voidClass = void.class;
            Class<Class> classClass = Class.class;
            Class<Double> doubleClass = Double.class;
            Class<Float> floatClass = Float.class;
            Class<Boolean> booleanClass = Boolean.class;
    

    java内存分析

    • 堆:
      • 存放new的对象和数组
      • 可以被所有线程共享,不会存放别的对象的引用
      • 存放基本数据类型
      • 存放引用对象的地址(引用在堆里面的具体地址)
    • 方法区(是一个特殊的堆)
      • 包含了所有的class和static变量
      • 可以被所有线程共享

    类加载的过程

    当程序主动使用某个类时,如果该类还没有被加载到内存中,系统就会通过以下三个步骤对该类进行初始化。

    1. 类的加载
      • 将类的class字节码文件加载到内存中,把静态数据转换成方法区的运行时数据,然后创建Class对象。这个过程由类加载器完成。
    2. 类的链接
      • 将类的二进制数据合并到jre中
        • 验证:确保加载的类符合JVM规范,不存在安全问题
        • 准备:为类变量分配内存并设置初始值,这些内存都在方法区中分配
        • 解析:虚拟机常量池内的常量名,替换为地址。
    3. 类的初始化
      • JVM负责对类进行初始化
        • 执行类构造器<clinit>()方法,负责构造类信息,不是构造该类的构造器
        • 初始化一个类的时候,如果发现父类还没有进行初始化,会先对父类进行初始化
        • JVM会保证一个类的<clinit>()方法在多线程环境中被正确加锁同步

    类加载器

    类加载器的作用:把类的class字节码文件加载到内存中,并且把静态数据转换成方法区的运行时数据,然后创建Class对象,作为方法区中类数据的访问入口。

    1. 类引导加载器:
      • C++编写的,JVM自带的,负责装载java平台核心库(rt .jar)。该加载器无法直接获取。
    2. 类扩展加载器:
      • 负责装载jre/lib。。下的jar包。
    3. 系统类加载器:
      • 负责java.class.path下的类和jar包的加载,是最常用的加载器
            ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        
            ClassLoader parent = systemClassLoader.getParent();
        
            ClassLoader parent1 = parent.getParent();
    

    获取当前类加载器:是最常用的系统类加载器

            //获取当前类的类加载器
            ClassLoader classLoader = Class.forName("reflect.Reflect").getClassLoader();
            System.out.println(classLoader);	
    

    获取类名:

            //获得类的名字
            System.out.println(aClass);//class + 包名+类名
            System.out.println(aClass.getName());//包名+类名
            System.out.println(aClass.getSimpleName());//类名
    

    获取属性:

            //获得类的属性
            System.out.println("============");
            //getFields()只能获取public属性
            Field[] field = aClass.getFields();
            for (Field pub:field) {
                System.out.println(pub);
            }
            //getDeclaredFields()获取所有的属性
            System.out.println("============");
            Field[] fields = aClass.getDeclaredFields();
            for (Field f:fields) {
                System.out.println(f);
            }
    

    获取方法:

            //获取该类的public方法和父类的public方法
            Method[] methods = aClass.getMethods();
            //获取该类的所有方法
            Method[] declaredMethods = aClass.getDeclaredMethods();
    

    获取构造器:

            //获取该类的public构造器
            Constructor<?>[] constructors = aClass.getConstructors();
    
            //获取该类的所有构造器
            Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
    

    通过反射动态创建对象

    有了Class类对象后,可以调用Class类对象的newInstance()方法,创建对象

    • 类必须有一个无参构造器
    • 类的构造器有足够的访问权限
            //通过无参构造创建对象
            Object o = aClass.newInstance();
    
            //通过构造器创建对象
            Constructor c = aClass.getDeclaredConstructor(String.class,int.class);
            Object newInstance = c.newInstance("柯柯", 18);
    

    通过反射操作方法:

            //通过反射操作方法
            Method setSss = aClass.getDeclaredMethod("setSss", String.class);
            setSss.invoke(newInstance,"kkkkkk");//传入对象 + 参数值
            System.out.println(newInstance);
    

    通过反射操作属性:

            //可以直接操作类的public属性
            Field sss = aClass.getDeclaredField("sss");
            sss.set(newInstance,"qqqqq");
            System.out.println(newInstance);
    
            //不能直接操作类的私有属性,需要关闭安全检测
            Field name = aClass.getDeclaredField("name");
            //设置为可进入的,可使用的,默认为false
            name.setAccessible(true);
            name.set(newInstance,"www");
            System.out.println(newInstance);
    

    通过反射获取注解:

            Class<?> aClass = Class.forName("reflect.User");
    
    //        通过过反射获取注解
            Annotation[] annotations = aClass.getDeclaredAnnotations();
            for (Annotation annotation: annotations) {
                System.out.println(annotation);
            }
    //        通过过反射获取注解的值
            DIY diy = aClass.getDeclaredAnnotation(DIY.class);
            System.out.println(diy.value());
    //        获得属性的注解
            Field name = aClass.getDeclaredField("name");
            DIYField diyField = name.getAnnotation(DIYField.class);
            System.out.println(diyField.value());
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface DIY{
        String value();
    }
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface DIYField{
        String value();
    }
    
  • 相关阅读:
    ASP.Net Core -- 模型验证
    C# -- nameof什么意思?
    C# -- value是什么意思?
    C# -- 异常(二)
    C# -- 异常(一)
    C# -- 委托(二)
    C# -- 委托(一)
    ASP.Net Core -- Controller返回View
    ASP.Net Core -- 中间件
    ASP.Net Core -- 服务注册和管道
  • 原文地址:https://www.cnblogs.com/qqkkOvO/p/13948398.html
Copyright © 2011-2022 走看看