• 注解与反射


    注解与反射

    一.注解(Annotation)

    作用:

    • 不是程序本身,可以对程序做出解释
    • 可以被其他程序(如编译器)读取

    格式

    以"@注释名"在代码中存在,还可以添加参数值

    内置注解

    package oop;
    import java.util.ArrayList;
    import java.util.List;
    public class annotation {
        @Override//重写的注解
        public String toString() {
            return super.toString();
        }
        @Deprecated //不推荐程序员使用,但是可以使用,或者存在更好的方式
        public static void test(){
            System.out.println("deprecated");
        }
        @SuppressWarnings("all")//镇压警告
        public void test2(){
            List list=new ArrayList<>();
        }
    
        public static void main(String[] args) {
            test();
        }
    }
    
    

    元注解

    元注解的作用是负责注解其他注解,Java定义了4个标准的meta-annotation类型,用来对其他annotation进行说明

    • @Target:用于描述注解的使用范围
    • @Retention:表示需要在说明级别保存该注释信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)
    • @Document:说明该注解将被包含在javadoc中
    • @Inherited:说明子类可以继承父类中的该注解
    package oop;
    import java.lang.annotation.*;
    @MyAnnotation
    public class annotation {
        //使用注解
        @MyAnnotation
        public void test(){
    
        }
    }
    //定义一个注解
    //Target 表示注解可以用在什么地方
    @Target(value= {ElementType.TYPE,ElementType.METHOD})
    //Rentention 表示注解在什么地方还有效
    @Retention(value = RetentionPolicy.RUNTIME)
    //Documented 表示是否将注解生成在javadoc中
    @Documented
    //Inherited 表示子类可以继承父类的注解
    @Inherited
    @interface MyAnnotation{
    
    }
    

    自定义注解

    使用@interface自定义注解是,自动继承了java.lang.annotation.Annotation接口

    • 格式@interface 注解名{定义内容}
    • 其中每一个方法实际上是声明了一个配置参数
    • 方法名称就是参数名称
    • 返回值类型就是参数的类型(返回值只能是基本型)
    • 可以通过default来声明参数默认值
    • 如果只有一个参数名,一般参数名为value
    • 注解元素必须要有值
    package oop;
    import java.lang.annotation.*;
    //自定义注解
    public class annotation {
        //注解可以显式赋值,如果没有默认值就必须给注解赋值
        @MyAnnotation()
        public void test(){
    
        }
    }
    
    @Target(value= {ElementType.TYPE,ElementType.METHOD})
    @interface MyAnnotation{
        //注解的参数:参数类型+参数名();
        String name() default "hhh";
    
    }
    
    

    二.反射(Reflection)

    动态语言:可以在运行时根据某些条件改变自身结构的语言
    静态语言:运行时结构不可变的语言
    java可以利用反射机制获得类似动态语言的特性

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

    package oop;
    import java.util.*;
    public class Test{
      public static void main(String[] args) throws ClassNotFoundException{
        //通过反射获取类的class对象
        Class c1=Class.forName("oop.User");
        Class c2=Class.forName("oop.User");
        Class c3=Class.forName("oop.User");
        System.out.println(c1);
        //一个类在内存中只有一个Class对象
        //一个类被加载后,类的整个结构都会被封装在Class对象中
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
      }
    }
    class User{
      private String name;
      private  int age;
    }
    

    获取Class类的实例

    • 若已知具体类,通过类的class属性获取
    • 若已知某个类的实例,调用该实例的getClass()方法获取Class对象
    • 若已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
    • 内置基本数据类型可以直接用类名.TYPE
    package oop;
    public class Test{
      public static void main(String[] args) throws ClassNotFoundException{
        System.out.println(User.class);
        User u1=new User();
        System.out.println(u1.getClass());
        Class c1=Class.forName("oop.User");
        System.out.println(c1);
        System.out.println(Integer.TYPE);
      }
    }
    class User{
      private String name;
      private  int age;
    }
    
    

    所有类型的Class对象

    package oop;
    import java.lang.annotation.ElementType;
    public class Test {
      public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Object.class;//类
        Class c2 = Comparable.class;//接口
        Class c3 = String[].class;//一维数组
        Class c4 = String[][].class;//二维数组
        Class c5 = Override.class;//注解
        Class c6 = ElementType.class;//枚举
        Class c7 = Integer.class;//基本类型
        Class c8 = void.class;//void
        Class c9 = Class.class;//Class
        System.out.println(c1 );
        System.out.println(c2 );
        System.out.println(c3 );
        System.out.println(c4 );
        System.out.println(c5 );
        System.out.println(c6 );
        System.out.println(c7 );
        System.out.println(c8 );
        System.out.println(c9 );
      }
    }
    
    

    只要元素类型与维度一样,Class对象也一样

    类加载

    package oop;
    import java.lang.annotation.ElementType;
    public class Test {
      public static void main(String[] args) throws ClassNotFoundException {
        A a=new A();
        System.out.println(a.m);
        /*
        1.加载到内存,会产生一个类对应Class对象
        2.链接,链接结束后,m的默认值为0;
        3.初始化
        <clinit>(){
        m=100;
        m=100
        }
         */
      }
    }
    class A{
      static int m=100;
      static {
        System.out.println("aa");
        m=200;
      }
    
      public A(){
        System.out.println("bb");
      }
    }
    
    

    什么时候会发生类的初始化

    1. 主动引用(一定会发生类的初始化)
      • 虚拟机启动,先初始化main方法所在的类;
      • new一个类的对象
      • 调用类的静态成员和静态方法(除了final常量)
      • 使用反射调用
      • 当初始化一个类时,如果其父类没有被初始化,则会先初始化它的父类
    2. 被动引用(不会发生类的初始化)
      • 访问一个静态域时,只有真正声明这个域的类才会被初始化;如通过子类引用父类的静态变量,只有父类会初始化
      • 通过数组定义类的引用,不会触发此类的初始化
      • 引用常量不会触发此类的初始化(因为其在链接阶段就存在常量池中)
    package oop;
    import org.w3c.dom.ls.LSOutput;
    
    import java.lang.annotation.ElementType;
    public class Test {
      static {
        System.out.println("main类被加载");
      }
      public static void main(String[] args) throws ClassNotFoundException {
        //主动引用
        //Son s=new Son();
        //反射也会产生主动引用
        //Class c1=Class.forName("oop.Son");
        //不会产生类的引用的方法,被动引用
        //通过子类调取父类的方法不会加载子类
        //System.out.println(Son.b);
        //通过数组定义也不会加载子类
        //Son[] sons=new Son[5];
        //引用类常量也不会加载子类
        //System.out.println(Son.c);
      }
    }
    class Father{
      static int b=3;
      static {
        System.out.println("父类被加载");
      }
    }
    class Son extends Father{
      static int a=10;
      static {
        System.out.println("子类被加载");
      }
      static final int c=90;
    }
    
    

    类的加载器

    package oop;
    public class Test {
      public static void main(String[] args) {
        //获得系统类的加载器(用户自定义类加载器)
        ClassLoader classLoader1 = ClassLoader.getSystemClassLoader();
        //获取系统类的加载器的父类加载器-->扩展类加载器
        ClassLoader classLoader2 = classLoader1.getParent();
        //获取扩展类加载器的父类加载器-->根加载器(核心类加载器,由C/C++编写,无法直接获取)
        ClassLoader classLoader3 = classLoader2.getParent();
        System.out.println(classLoader1);
        System.out.println(classLoader2);
        System.out.println(classLoader3);
      }
    }
    

    动态创建对象执行方法

    package oop;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class Test {
      public static void main(String[] args) throws Exception{//获得Class对象
         Class c1=Class.forName("oop.User");
         //构造对象
         // user=(User)c1.newInstance();//调用无参构造器
         // System.out.println(user);
        //有参构造
         Constructor constructor=c1.getDeclaredConstructor(String.class,int.class);
         User user=(User)constructor.newInstance("dengwenxiong",19);
         System.out.println(user);
         //通过反射获取方法,并调用;
        Method eat=c1.getDeclaredMethod("eat",String.class);
        //激活
        eat.invoke(user,"苹果");
        Field name=c1.getDeclaredField("name");
        name.setAccessible(true);//取消安全检测,可以操作私有属性
        System.out.println(name.get(user));
      }
    }
    class User{
      private int age;
      private String name;
      public User(String name,int age){
        this.name=name;
        this.age=age;
      }
      public void eat(String food){
        System.out.println("正在吃"+food);
      }
    }
    
    
    

    setAccessible关闭检测可以提高程序效率

    获取注解信息

    package oop;
    
    import java.lang.annotation.*;
    import java.lang.reflect.Field;
    
    public class Test {
      public static void main(String[] args) throws Exception{
        Class c1=Class.forName("oop.User");
        Annotation[] annotations=c1.getAnnotations();
        for(Annotation annotation:annotations){
          System.out.println(annotation);
        }
        ToUser user=(ToUser)c1.getAnnotation(ToUser.class);
        String value=user.value();
        System.out.println(value);
        Field age=c1.getDeclaredField("age");
        ToFiled f=age.getAnnotation(ToFiled.class);
        System.out.println(f.columnName());
        System.out.println(f.length());
        System.out.println(f.type());
    
      }
    }
    @ToUser("user_table")
    class User{
      @ToFiled(columnName = "user_age",type="int",length = 10)
      private int age;
      private String name;
      public User(String name,int age){
        this.name=name;
        this.age=age;
      }
      public void eat(String food){
        System.out.println("正在吃"+food);
      }
    }
    //类名的注解
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface ToUser{
      String value();
    }
    //属性的注解
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface ToFiled{
      String columnName();
      String type();
      int length();
    }
    
    
    
    
  • 相关阅读:
    ASP.NET 动态创建文本框 TextBox (add TextBox to page dynamically)
    SQL Server 行列转换
    NPOI把Excel导入到数据库
    Net操作Excel(终极方法NPOI)
    mongdo通用类(C#版)
    ORACLE 定时执行存储过程
    C# Excel导入、导出
    网络爬虫+HtmlAgilityPack+windows服务从博客园爬取20万博文
    Git初级使用教程
    asp.net+swfupload 多图片批量上传(附源码下载)
  • 原文地址:https://www.cnblogs.com/python-road/p/13220875.html
Copyright © 2020-2023  润新知