Java注解和反射相关知识总结

注解

与声明一个"Class"不同的是,注解的声明使用 @interface 关键字。一个注解的声明如下:

/**
 - Created by Alex on 12/1/20
 */
public @interface PassengerType {
}

元注解:作用在注解上的注解

@Target
  • ElementType.ANNOTATION_TYPE 可以应用于注解类型。
  • ElementType.CONSTRUCTOR 可以应用于构造函数。
  • ElementType.FIELD 可以应用于字段或属性。
  • ElementType.LOCAL_VARIABLE 可以应用于局部变量。
  • ElementType.METHOD 可以应用于方法级注解。
  • ElementType.PACKAGE 可以应用于包声明。
  • ElementType.PARAMETER 可以应用于方法的参数。
  • ElementType.TYPE 可以应用于类的任何元素。
@Retention
  • RetentionPolicy.SOURCE - 标记的注解仅保留在源码级别中,并被编译器忽略。作用于源码级别的注解,可提供给IDE语法检查、APT等场景使用。
  • RetentionPolicy.CLASS - 标记的注解在编译时由编译器保留,但 Java 虚拟机(JVM)会忽略。
  • RetentionPolicy.RUNTIME - 标记的注解由 JVM 保留,因此运行时环境可以使用它。
/**
 * Created by Alex on 12/1/20
 * 注意:在使用注解时,如果定义的注解中的类型元素无默认值,则必须进行传值。
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface PassengerType {
    String value(); //无默认值
    int age() default 1; //有默认值

}
RetentionPolicy.SOURCE
IDE语法检查

在Android开发中, support-annotations 与 androidx.annotation) 中均有提供 @IntDef 注解,此注解的定义如
下:

@Retention(SOURCE) //源码级别注解 @Target({ANNOTATION_TYPE}) 
public @interface IntDef { 
   int[] value() default {};
   boolean flag() default false;
   boolean open() default false; 
}

Java中Enum(枚举)的实质是特殊单例的静态成员变量,在运行期所有枚举类作为单例,全部加载到内存中。
比常量多5到10倍的内存占用。

此注解的意义在于能够取代枚举,实现如方法入参限制。

/**
 * Created by Alex on 12/2/20
 */
public enum Passenger {
    CHILD,ADULT
}

class PassengerTest{
    public static void main(String[] args) {
        setData(Passenger.CHILD);
    }
  
    public static void setData(Passenger p){
        
    }
}

优化内存采用注解的方式,且带语法检查:

/**
 * Created by Alex on 12/14/20
 */

@IntDef({IdType.IDCARD, IdType.PASSPORT,IdType.OHTERS})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.PARAMETER})
public @interface IdType {
    /**
     * 身份证
     */
    int IDCARD = 1;
    /**
     * 护照
     */
    int PASSPORT = 2;
    /**
     * 其他
     */
    int OHTERS = 8;

//调用处
private fun getResult(ic:HSIDCardInfo,@IdType type:Int){
}
 getResult(ic,IdType.IDCARD)
 这个地方就必须是注解里定义的类型,随便传123的话编译会提示非法

}
APT注解处理器

APT全称为:“Anotation Processor Tools”,译为注解处理器。顾名思义,其用于处理注解。编写好的Java源文
件,需要经过 javac 的编译,翻译为虚拟机能够加载解析的字节码Class文件。注解处理器是 javac 自带的一个工
具,用来在编译时期扫描处理注解信息。你可以为某些注解注册自己的注解处理器。 注册的注解处理器由 javac
调起,并将注解信息传递给注解处理器进行处理

RetentionPolicy.CLASS

定义为 CLASS 的注解,会保留在class文件中,但是会被虚拟机忽略(即无法在运行期反射获取注解)。此时完全符合
此种注解的应用场景为字节码操作。如:AspectJ、热修复Roubust中应用此场景。
所谓字节码操作即为,直接修改字节码Class文件以达到修改代码执行逻辑的目的。在程序中有多处需要进行是否
登录的判断。

//Java源码 
@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.CLASS)
public @interface Login { }
@Login 
public void jumpA(){
 startActivity(new Intent(this,AActivity.class)); 
 }
public void jumpB(){
 startActivity(new Intent(this,BActivity.class)); 
 }

在上诉代码中, jumpA 方法需要具备登录身份。而 Login 注解的定义被设置为 CLASS 。因此我们能够在该类所编译的字节码中获得到方法注解 Login 。在操作字节码时,就能够根据方法是否具备该注解来修改class中该方法的内容加入 if-else 的代码段:(其实就是AOP切面)

//Class字节码 
@Login 
public void jumpA() {
 if (this.isLogin) {
  this.startActivity(new Intent(this, LoginActivity.class)); 
   } else {
   this.startActivity(new Intent(this, AActivity.class)); 
   } 
}
RUNTIME
注解保留至运行期,意味着我们能够在运行期间结合反射技术获取注解中的所有信息。

反射

Java反射机制主要提供了以下功能
  • 在运行时构造任意一个类的对象
  • 在运行时获取或者修改任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法(属性)
获取Class对象的三种方式
  • 通过类名获取 类名.class
  • 通过对象获取 对象名.getClass()
  • 通过全类名获取 Class.forName(全类名),classLoader.loadClass(全类名)
//使用 Class 类的 forName 静态方法
public static Class<?> forName(String className)

//直接获取某一个对象的 class
Class<?> klass = int.class; 
Class<?> classInt = Integer.TYPE;

//调用某个对象的 getClass() 方法
StringBuilder str = new StringBuilder("123"); 
Class<?> klass = str.getClass();
创建实例
//使用Class对象的newInstance()方法来创建Class对象对应类的实例。
Class<?> c = String.class; 
Object str = c.newInstance();

//先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

Class<?> c = String.class; 
//获取String类带一个String参数的构造器 
Constructor constructor = c.getConstructor(String.class); 
//根据构造器创建实例 
Object obj = constructor.newInstance("23333"); 
System.out.println(obj);

得到构造器的方法
Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的public构造函数(包括父类) 
Constructor[] getConstructors() -- 获得类的所有公共构造函数 
Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(包括私有) 
Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)
获得字段信息的方法
Field getField(String name) -- 获得某public(且只能是public)字段 包括父类、父类的父类等
Field[] getFields() -- 获得类的所有public(且只能是public字段  包括父类、父类的父类等
Field getDeclaredField(String name) -- 获得某字段,包括私有,但不包括父类
Field[] getDeclaredFields() -- 获得类声明的所有字段,包括私有但不包括父类
获得方法信息的方法
//跟上面的获取属性同理
Method getMethod(String name, Class[] params) 
Method[] getMethods()
Method getDeclaredMethod(String name, Class[] params)  
Method[] getDeclaredMethods() 

一个通过注解和反射实现的view注入的demo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alex_ChuTT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值