初试注解 自定义实现FindViewById

本文深入浅出地介绍了Java注解的基本概念与使用方法,包括注解的定义、赋值、元注解及其应用场景,并通过实例演示了如何利用注解实现findViewById和布局设置的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一直忙着机器学习,博客停了许久

今天记录下注解的小代码


关于注解,一直在使用,了解少许,没有时间总结,这里记录下,共勉


注解包含太多了, 这里只记录下基本的语法 和使用


1 定义声明

    通过 @interface 关键字进行定义

   public @interface testInject {
   }
    结构与接口声明类似 ,仅仅多了个@  。上面就定义了个名为testInject的注解。

    注解里只有属性,没有方法, 属性以“无形参的方法”形式来声明,其方法为属性名,其返回值为属性类型。

    注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。

   public @interface testInject {

        int id();

        String text();
    }
   上面代码定义了 TestInject 这个注解中拥有 id 和 msg 两个属性。在使用的时候,我们可以给它们进行赋值    

   注解时可以对定义属性进行默认赋值,当无赋值时他们的值就是定义默认值  默认值需要用 default 关键值指定

   public @interface testInject {

        int id() default  -1;;

        String text()  default "ruiyi";
    }
2 注解的赋值
   赋值的方式是在注解的括号内以 value=”” 形式,多个属性之前用 ,隔开。

    @testInject(id = 4, text = "world")
    public class Test{

    }
   因为有默认值,所以无需要再在 @TestInject 后面的括号里面进行赋值了,这一步可以省略。
   @testInject()
    public class Test{

    }
  另外,还有一种情况。如果一个注解内仅仅只有一个属性时,应用这个注解时可以直接接属性值填写到括号内
   @testInject(4)
    public class Test{

    }
3 元注解
  元注解是可以注解到注解上的注解,或者说元注解对注解进行解释说明

元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

  3.1

  @Retention  注解的生命周期。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。
  它的取值如下:
      RetentionPolicy.SOURCE 在源文件中有效(即源文件保留),在编译器进行编译时它将被丢弃忽视。 
      RetentionPolicy.CLASS 在class文件中有效(即class保留),它并不会被加载到 JVM 中。 
      RetentionPolicy.RUNTIME 在运行时有效(即运行时保留),它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

  3.2

  @Documented
   顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

  3.3

  @Target 指定了注解运用的地方。
   @Target 有下面的取值
    ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
    ElementType.CONSTRUCTOR 用于描述构造器
    ElementType.FIELD 可以给属性进行注解
    ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
    ElementType.METHOD 可以给方法进行注解
    ElementType.PACKAGE 可以给一个包进行注解
    ElementType.PARAMETER 可以给一个方法内的参数进行注解
    ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

 3.4

   @Inherited
       Inherited 继承,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

   3.5

   @Repeatable
      Repeatable 自然是可重复的意思 (有时间详解)


4 初试  这里我们以注解的形式 来模拟findViewById的操作。

   4.1 定义注解

        控件注解

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

/**
 * Created by ruiyi on 2017/8/10.
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
    int value() default -1;
}
     //布局注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by ruiyi on 2017/8/10.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface LayoutInject {
    int value() default -1;
}
    4.2定义一个注解基类
package ruiyi.testInject;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import java.lang.reflect.Field;

/**
 * Created by ruiyi on 2017/8/10.
 */

public class InJectActivity extends AppCompatActivity {

    private int mLayoutId = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        InjectLayout();
        InjectView();
    }

    /**
     * 注解布局Layout id
     */
    private void InjectLayout() {
        Class<?> clazz = this.getClass();
        if (clazz.getAnnotations() != null) {
            if (clazz.isAnnotationPresent(LayoutInject.class)) {
                LayoutInject inject = clazz.getAnnotation(LayoutInject.class);
                mLayoutId = inject.value();
                setContentView(mLayoutId);
            }
        }

    }

    /**
     * 解析注解view id
     */
    private void InjectView() {
        if (mLayoutId <= 0)
            return;

        Class<?> clazz = this.getClass();
        Field[] fields = clazz.getDeclaredFields();//获得成员变量
        for (Field field : fields) {
            //判断是否有注解
            try {
                if (field.getAnnotations() != null) {
                    if (field.isAnnotationPresent(ViewInject.class)) {//如果属于这个注解为这个控件设置属性
                        field.setAccessible(true);//允许修改反射属性
                        ViewInject inject = field.getAnnotation(ViewInject.class);
                        field.set(this, this.findViewById(inject.value()));
                    }
                }
            } catch (Exception e) {
                Log.e("ASDFGHJKL", "not found view id!");
            }
        }
    }

}
   4.3 具体类
package ruiyi.testInject;

import android.os.Bundle;
import android.widget.TextView;

@LayoutInject(R.layout.activity_main)
public class MainActivity extends InJectActivity {

    @ViewInject(R.id.tv)
    TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mTextView.setText("ruiyi");
    }
}

上面就以注解实现了findViewById 和 布局setContent功能。

我这里赘述一点,解释下

    首先LayoutInject, 我们定义有效期为运行时,target为tyoe,作用在类上使用,类型为int值,默认-1,赋值代码@LayoutInject(R.layout.activity_main) 相当于@LayoutInject(value = R.layout.activity_main) , 取值时,因为指向类,LayoutInject inject = clazz.getAnnotation(LayoutInject.class); 类对象直接取注解对象,然后mLayoutId = inject.value();  取属性值, 最后setContentView(mLayoutId);

    再说ViewInject, 定义也是运行时,作用在属性上FIELD, 由于是属性,所以取时首先获取属性,也就是clazz.getDeclaredFields();//获得成员变量,由于反射机制,防止是private的field.setAccessible(true);//允许修改反射属性


就这样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值