java的反射机制 和 注解的原理理解

注解的概念:

注解:就是特殊的接口。@interface

@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {}

在Java中,注解类型(Annotation Type)和注解属性值(Annotation Attribute Value)是注解的两个关键概念:

1.注解类型:

注解类型指的是自定义注解的定义。在Java中,注解类型是一种特殊的接口类型,用@interface关键字来声明,定义了一组用于描述元数据信息的方法。这些方法通常称为注解的成员方法或属性方法,可以有返回值,并且可能包含默认值。例如:

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
    String value() default "";
    int count() default 1;
}

MyAnnotation就是一个自定义注解类型,其中定义了两个属性方法value()count()

2.注解属性值

注解属性值指的是在使用注解时为属性赋予的值。当我们在类、方法、字段等元素上使用注解时,可以通过属性名=属性值的形式为注解的属性赋值。例如:

@MyAnnotation(value = "Hello", count = 3)
public class MyClass {
    // class body
}

注解的分类

一.JDK内置的注解:

  • @Override 检测重写

  • @Deprecated 已过时, 只是一个标志, 还是能够使用

  • @SuppressWarnings("all") 抑制编译器生成警告信息

二.元注解:

在注解上使用,比如:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
  1. @Target  用来表示注解用在什么地方     
    • ElementType.PACKAGE 用于描述包
    • ElementType.FIELD 用户描述成员变量、对象、属性(包括enum实例)
    • ElementType.PARAMETER:用于描述参数
    • ElementType.TYPE:用于描述类、接口(包括注解类型) 或enum声明
    • ElementType.CONSTRUCTOR:用于描述构造器 
    • ElementType.LOCAL_VARIABLE:用于描述局部变量 
    • public enum ElementType {
          /** Class, interface (including annotation type), or enum declaration */
          TYPE,
      
          /** Field declaration (includes enum constants) */
          FIELD,
      
          /** Method declaration */
          METHOD,
      
          /** Formal parameter declaration */
          PARAMETER,
      
          /** Constructor declaration */
          CONSTRUCTOR,
      
          /** Local variable declaration */
          LOCAL_VARIABLE,
      
          /** Annotation type declaration */
          ANNOTATION_TYPE,
      
          /** Package declaration */
          PACKAGE,
      
          /**
           * Type parameter declaration
           *
           * @since 1.8
           */
          TYPE_PARAMETER,
      
          /**
           * Use of a type
           *
           * @since 1.8
           */
          TYPE_USE
      }
  2. @Retention 什么时候使用该注解 (保留期)
    • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。

    • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。

    • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

    • public enum RetentionPolicy {
          /**
           * Annotations are to be discarded by the compiler.
           */
          SOURCE,
      
          /**
           * Annotations are to be recorded in the class file by the compiler
           * but need not be retained by the VM at run time.  This is the default
           * behavior.
           */
          CLASS,
      
          /**
           * Annotations are to be recorded in the class file by the compiler and
           * retained by the VM at run time, so they may be read reflectively.
           *
           * @see java.lang.reflect.AnnotatedElement
           */
          RUNTIME
      }
    • 自定义注解 Retention 一定要设置为RUNTIME,这样才能反射获取,不然运行的时候不能反射
  3. @Documented  注解是否将包含在JavaDoc中
    • 一个简单的Annotations标记注解,表示是否将注解信息添加在javadoc文档中
  4. @Inherited 定义该注释和子类的关系
    • Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解

注解的原理:

如果理解注解的原理,首先需要知道几个知识点,接口的向上转型,java的反射机制,JDK动态代理机制。

一.接口的向上转型

举例理解:

1.定义一个接口

package 接口向上转型;
 
public interface Mather {
	
	int AGE = 48;
	
	public abstract void sayAge();
	
}

2.接口的实现类

package 接口向上转型;
 
public class Daughter implements Mather{
	
	public int age = 18;
	public String sex = "女";
	
	@Override
	public void sayAge() {
		System.out.println("我的年龄是:"+age);
	}
	
	public void saySex() {
		System.out.println("我的性别是:"+sex);
	}
 
}

3.测试类

package 接口向上转型;
 
public class Test {
 
	public static void main(String[] args) {
	
		
		System.out.println("----------");
		
		Daughter daughter = new Daughter();
		System.out.println(daughter.age);
		daughter.sayAge();
		System.out.println(daughter.sex);
		daughter.saySex();
		
		System.out.println("------输出向上转型后的,属性和方法------");
		Mather a = new Daughter();
		System.out.println(a.AGE);
		// a 没有了sex属性
		a.sayAge();
		// a 没有了saySex方法
	}
 
}

4.输出结果为:

----------
18
我的年龄是:18
女
我的性别是:女
------输出向上转型后的,属性和方法------
48
我的年龄是:18
我女儿18岁

总结:

1.Mather a = new Daughter();就是接口向上转型的体现

2. a.AGE 是接口中常量数据,也就是48

3.调用的方法一定是实现类的方法。即 a.sayAge();调用的是实现类

二. java的反射机制(看到反射,就要想到动态,运行

如果理解java的反射机制,首先梳理几个概念:类加载 ,类加载器  class类, class对象, 实例对象。

class类概念:

        在Java中,每一个都对应着一个Class对象,这个Class对象包含了类的相关信息,例如类的名称、继承关系、方法、字段、注解等信息。通过Class对象,可以获取类的各种信息并对其进行操作(有点反射的意思啦)。

Class对象的产生:

        每一个都对应着一个Class对象,那么Class对象怎么生成的呢?答案是:当类的字节码文件被加载到内存中就创建了这个类的Class对象。Java只有在需要使用类时,才会触发该类的加载。

类加载:

        类加载是指将类的字节码加载到 Java 虚拟机(JVM)中并转换为相应的 Class 对象的过程。在 Java 中,类加载是 Java 虚拟机运行时的一部分,它负责动态地加载类并创建类的实例。class对象 对应 运行时的类。

类加载器:

        类加载器(ClassLoader)负责执行类加载的任务。当 JVM 需要加载一个类时,它会委托给类加载器去完成。类加载器根据类的名称查找类的字节码文件(通常是 .class 文件),然后将字节码加载到内存中,并转换为相应的 Class 对象。

Java中触发类加载的情况:

  1. 创建一个类的实例,包括通过new关键字创建、反射创建、反序列化等方式。

  2. 访问类的静态变量或方法。

  3. 通过Class.forName()方法加载类。

  4. 使用ClassLoader.loadClass()方法加载类。

  5. 使用Java虚拟机启动时指定的主类会被加载和初始化。

获取Class对象的方法:

     Java中有三种获取Class对象的方法:

  1. 对象.getClass()方法:调用对象的getClass()方法来获取Class对象。
  2. 类名.class:使用类名.class语法来获取Class对象。
  3. Class.forName()方法:使用Class.forName()方法来动态加载指定类,并返回其Class对象。

Class类的应用场景:

     在Java中,Class类的应用场景非常广泛,例如:

  1. 反射机制:通过Class对象获取的相关信息,并在运行时动态创建对象、访问方法、字段、注解等信息。
  2. 类加载机制:在Java中,每一个类都是在第一次使用时动态加载到JVM中的,Class对象就是用来表示这个类的。
  3. 泛型:泛型中的T表示类型参数,可以通过Class类来获取T的实际类型。

Class类的常见函数:

  1. getName()方法:获取类的全限定名。
  2. getSuperclass()方法:获取类的父类。
  3. getDeclaredFields()方法:获取类的所有字段,包括私有字段。
  4. getFields()方法:获取类的所有public字段。
  5. getDeclaredMethods()方法:获取类的所有方法,包括私有方法。
  6. getMethods()方法:获取类的所有public方法。

        总结:每一个类都对应着一个Class对象,每一个类的所有对象(实例对象)都是由它对应的这个Class对象创建的。正常顺序是class类——》class对象。反射机制是通过Class对象获取的相关信息,并在运行时动态创建对象、访问方法、字段、注解等信息。

三.JDK动态代理机制

四.注解的理解

编译的时候会把注解的信息,写到使用注解的类,的字节码中(jdk内置的注解不会写进去,只在编译的时候进行校验)

注解在字节码文件中是如何存储的?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值