lengjingbuliaoyidian
文章8
标签6
分类5
注解和反射

注解和反射

注解的含义:

  • Annotation的作用:不是程序本身,可以对程序做出解释;可以被其他程序(比如:编译器等)读取,注解可以用来修饰类、方法、变量、参数等,可以用来检查代码质量、约束开发者的编程风格、提高代码的可读性和可维护性(检查、约束)。
  • 格式:以“@注释名”在代码中存在,还可以在后面添加一些参数值
  • 使用范围:可以附加在package、class、method、filed等上面,相当于给他们添加了额外的辅助信息,可以通过反射机制编程实现对这些元数据的访问

内置注解:

  • @Override: 定义在java.lang.Override中,此注解只适用于修饰方法,表示一个方法声明打算重写超类中的另外一个方法声明。

  • @Deprecated:定义在Java.lang.Deprecated中,此注解可以用于修饰方法,属性,类,表示不鼓励程序员使用这样的元素(通常事因为它很危险或者存在更好的选择),但是可以此方法可以运行。

  • @SuppressWarnings:定义在Java.lang.SuppressWarnings中,用来抑制编译时的警告信息(后面要有参数才能正确使用),例如:

      @SuppressWarnings("all");
      @SuppressWarnings("unchecked");
      @SuppressWarnings("unchecked","deprecation");
    

元注解:

  • 作用:负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明。

  • 类型:@Target ,@Retention, @Documented ,@Inherited (这些类型和他们所支持的类在Java。狼。annotation包中可以找到。)

          @Target:用于描述注解的使用范围(即被描述的代码可以用在那些地方)
    
          @Retention:表示需要在说明级别保存该注解信息,用于描述注解的生命周期(Runtime>class>source)
          @Document:说明该注解将被包含在Javadoc 中
          @Inherited:说明子类可以继承父类中的该注解
    
  • 格式:
    @Target(value ={ElementType.METHOD,ElementType.TYPE})
    @Retention(value=RetentionPolicy.RUNTIME)

自定义注解:

  • 用法:使用@interface自定义注解时,自动继承java.lang.annotation.Annotation接口
  • 归纳:
  1. @interface用来声明一个注解,格式:public @interface 注解名{定义内容}
  2. 其中的每一个方法实际上是声明一个配置参数
  3. 方法的名称就是参数的名称
  4. 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
  5. 可以通过default来声明参数的默认值
  6. 如果只有一个参数成员,一般参数名为value
  7. 注解元素必须要由值,定义注解元素时,经常使用空字符串0作为默认值
  • 代码如下:
    package com.st.test;

    //测试自定义注解

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;

    public class Test03 {
    //注解可以显示赋值,如果没有默认值(default 数值),我们就必须给注解赋值
    @MyAnnotation2(name=”李明” ,schools ={“湖南大学”,”清华大学”} )
    public void test(){}

    //如果自定义的注解只有一个值的时候可以使用value表示,在方法注解表示的时候可以直接省略value
    @MyAnnotation3(“李明”)
    public void test2(){}
    }

    @Target(value={ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation2{
    //注解的参数:参数类型+参数名();
    String name() ; //赋值为李明
    int age() default 0;
    int id() default -1; //如果默认值为-1,则代表不存在

    String[] schools();
    }
    @Target(value={ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation3{
    String value();
    }

java反射

  • 特点:Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得此类似动态语言的特性。Java的动态性让在编程的时候更加灵活!

  • 反射:被视为是动态语言的关键,反射机制允许程序在执行期间借助于’Reflection API’获取任何类的内部信息,并直接操作任意对象的内部属性及方法

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

    加载完类之后,在堆内存的方法中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,通过镜子看到类的结构,所以形象的称为:反射

  • 对比:

  1. 正常的方式:先引用需要的“包类”名称——> 通过new实例化——> 取得实例化对象
  2. 反射方式: 实例化对象——> getClass()方法——> 得到完整的“包类”名称。
  • 反射机制在运行时提供的功能:
  1. 判断任意一个对象所属的类
  2. 可构造任意一个类的对象
  3. 可判断任意一个类所具有的成员变量和方法
  4. 可获取泛型信息
  5. 可调用任意一个对象的成员变量和方法
  6. 可处理注解
  7. 生成动态代理(AOP)
  • 创建对象的五种方式: new、newInstance、clone、反序列化、反射。

  • 代码:

        package com.st.reflection;
        public class Test002 {
        public static void main(String[] args) throws ClassNotFoundException {
      //通过反射获取类的Class对象
     Class c1=Class.forName("com.st.reflection.User");
      System.out.println(c1);
    
     //查看他们是不是属于同一个类,就可以查看他们的哈希一不一样
      Class c2=Class.forName("com.st.reflection.User");
      Class c3=Class.forName("com.st.reflection.User");
      Class c4=Class.forName("com.st.reflection.User");
     //结果是一样的
      //一个类在内存中只有一个Class对象,一个类被加载之后,类的整个结构都会被封装在Class对象中
      System.out.println(c2.hashCode());
      System.out.println(c3.hashCode());
      System.out.println(c4.hashCode());
       }
    }
      
      //实体类:pojo entity
      class User{
       private String name;
       private int id;
       private  int age;
    
      public User(){
    
       }
      public User(String name, int id, int age) {
      this.name = name;
      this.id = id;
      this.age = age;
      }
    
      public String getName() {
          return name;
      }
    
      public int getId() {
          return id;
      }
    
      public int getAge() {
          return age;
      }
    
      public void setName(String name) {
          this.name = name;
      }
    
      public void setId(int id) {
          this.id = id;
      }
    
      public void setAge(int age) {
          this.age = age;
      }
    
      @Override
      public String toString() {
          return "User{" +
                  "name='" + name + '\'' +
                  ", id=" + id +
                  ", age=" + age +
                  '}';
      }
    }
    

获取Class类的实例

  • 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高

              Class clazz =Person.class;
    
  • 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException

              Class clazz=Class.forName("demo01.Student");
    
  • 已知某个类的实例,调用实例的getClass()方法获取Class对象

              Classclazz=person.getClass();
    
  • 内置基本数据类型可以用类名.TYPE

  • 还可以利用ClassLoader

  • 综合示例:

              package com.st.reflection;
              //测试Class 类的创建方式有哪些
              public class Test003 {
                  public static void main(String[] args) throws ClassNotFoundException {
                      Person person=new Student();
                      System.out.println("这个人是:"+person.name);
    
                      //方式一:通过对象获得
                      Class c1=person.getClass();
                      System.out.println(c1.hashCode());
    
                      //方式二:通过forname获得
                      Class c2 = Class.forName("com.st.reflection.Student");
                      System.out.println(c2.hashCode());
    
                      //方式三:通过类名。class 获得
                      Class<Student> c3 = Student.class;
                      System.out.println(c3.hashCode());
    
                      //方式四:基本内置类型的包装类都有一个Type属性
                      Class c4=Integer.TYPE;
                      System.out.println(c4.hashCode());
    
                      //获取父类类型
                      Class c5=c1.getSuperclass();
                      System.out.println(c5);
    
    
                  }
              }
    
              class Person{
                  public String name;
                  public Person(){
    
                  }
    
                  public Person(String name) {
                      this.name = name;
                  }
    
                  @Override
                  public String toString() {
                      return "Person{" +
                              "name='" + name + '\'' +
                              '}';
                  }
              }
    
              class Student extends Person{
                  public Student(){
                      this.name="学生";
                  }
              }
              class Teacher extends Person{
                  public Teacher() {
                      this.name="老师";
                  }
              }
    

哪些类型可以有Class对象

  1. class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
  2. interface:接口
  3. []:数组(多维)
  4. enum:枚举
  5. annotation:注解@interface
  6. primitive type:基本数据类型
  7. void
本文作者:冷静不了一点
本文链接:http://example.com/2024/12/25/%E6%B3%A8%E8%A7%A3%E5%92%8C%E5%8F%8D%E5%B0%84/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可