两种注解的基本使用

首先介绍下注解的基本知识,详细使用方法请自行百度
首先注解分为三类:
标准 Annotation,元 Annotation,自定义 Annotation
(1).标准 Annotation
包括 Override, Deprecated, SuppressWarnings,是java自带的几个注解,他们由编译器来识别,不会进行编译,
不影响代码运行,至于他们的含义不是这篇博客的重点,这里不再讲述。
(2).元 Annotation
@Retention, @Target, @Inherited, @Documented,它们是用来定义 Annotation 的 Annotation。也就是当我们要自定义注解时,需要使用它们。
(3).自定义 Annotation
根据需要,自定义的Annotation。而自定义的方式,下面我们会讲到。
同样,自定义的注解也分为三类,通过元Annotation - @Retention 定义:
@Retention(RetentionPolicy.SOURCE)
源码时注解,一般用来作为编译器标记。如Override, Deprecated, SuppressWarnings。
@Retention(RetentionPolicy.RUNTIME)
运行时注解,在运行时通过反射去识别的注解。
@Retention(RetentionPolicy.CLASS)
编译时注解,在编译时被识别并处理的注解

这里主要介绍下运行时注解,和编译时注解。

所谓运行时注解是指,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;所以注解信息会加入到class文件中,在使用的时候通过反射方法拿到注解的传递数值.这就是为什么说,使用注解会影响性能,就是因为使用了反射。下面通过一个简单例子进行解释说明。
编写注解,含有名字name,年龄age ,年龄设置有默认值10

 @Target({ElementType.TYPE,ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Deanitation {
    String name();
    int age() default 10;
}

@Retention(RetentionPolicy.RUNTIME)表示该注解是运行时注解,@Target({ElementType.TYPE,ElementType.FIELD, ElementType.METHOD})表示该注解能作用的范围,

在类中使用方法如下:

 @Deanitation(name ="test")
public class Test {
    @Deanitation(name = "run",age = 17)
    public void run(){
        System.out.print("run");
    }
}

然后在Main方法执行过程中通过反射获取注解标注的信息:

public static void main(String[] args) {
        try {
            Class c=Class.forName("com.zhujie.Test");
            //2.判断类上是否存在注解,并获取类上面注解的实例
            if(c.isAnnotationPresent(Deanitation.class)){
                Deanitation Description = (Deanitation) c.getAnnotation(Deanitation.class);
                System.out.println(Description.name());
                System.out.println(Description.age());
            }
            //3.判断方法上是否存在注解,并获取方法上面注解的实例
            Method[] ms = c.getMethods();
            for (Method method : ms) {
                if(method.isAnnotationPresent(Deanitation.class)){
                    Deanitation Description = (Deanitation)method.getAnnotation(Deanitation.class);
                    System.out.println(Description.name());
                    System.out.println(Description.age());
                }
            }
            //另一种获取方法上的注解的解析方法
            for (Method method : ms) {
                Annotation[] as = method.getAnnotations();
                for (Annotation annotation : as) {
                    if(annotation instanceof Deanitation){
                        System.out.println(((Deanitation) annotation).name());
                        System.out.println(((Deanitation) annotation).age());
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

以上就是运行时注解使用的基本方法,应为在使用过程中使用反射,所以对性能有影响,使用范围也有限制。下面模拟ButterKnife的使用过程,说明下编译时注解的使用。
建立项目后,因为要继承AbstractProcessor编写自定义注解解释器,所以要建立一个javalib的module,在改module下编写注解类DebindVeiw

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface DeBindView {
    int value();
}

下面编写自定义注解解释器,主要是继承AbstractProcessor重写process方法,其中核心步骤是获取注解集合,然后生成所需要的java文件

 @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        messager.printMessage(Diagnostic.Kind.NOTE, "process...");
        mProxyMap.clear();
        Set<? extends Element> elesWithBind = roundEnv.getElementsAnnotatedWith(DeBindView.class);
        for (Element element : elesWithBind) {
            checkAnnotationValid(element, DeBindView.class);

            VariableElement variableElement = (VariableElement) element;
            //class type
            TypeElement classElement = (TypeElement) variableElement.getEnclosingElement();
            //full class name
            String fqClassName = classElement.getQualifiedName().toString();
            messager.printMessage(Diagnostic.Kind.NOTE, fqClassName);
            ProxyInfo proxyInfo = mProxyMap.get(fqClassName);
            if (proxyInfo == null) {
                proxyInfo = new ProxyInfo(elementUtils, classElement);
                mProxyMap.put(fqClassName, proxyInfo);
            }
            DeBindView bindAnnotation = variableElement.getAnnotation(DeBindView.class);
            int id = bindAnnotation.value(); /**获取View iD**/
            proxyInfo.injectVariables.put(id, variableElement);
        }
        /**
         * 生成所需要的java类
         */
        for (String key : mProxyMap.keySet()) {
            ProxyInfo proxyInfo = mProxyMap.get(key);
            try {
                JavaFileObject jfo = processingEnv.getFiler().createSourceFile(
                        proxyInfo.getProxyClassFullName(),
                        proxyInfo.getTypeElement());
                Writer writer = jfo.openWriter();
                writer.write(proxyInfo.generateJavaCode());
                writer.flush();
                writer.close();
            } catch (IOException e) {
                error(proxyInfo.getTypeElement(),
                        "Unable to write injector for type %s: %s",
                        proxyInfo.getTypeElement(), e.getMessage());
            }

        }
        return true;
    }

下面生成的java文件
根据注解生成的类
当然还要编写使用的API,我们要新建一个android lib module 在里面编写一个注册类,通过反射初始化 生成的类。达到初始化view findviewById()作用。

public class ViewInjector {
    private static final String SUFFIX = "$$ViewInject";

    public static void injectView(Activity activity) {
        ViewInject proxyActivity = findProxyActivity(activity);
        proxyActivity.inject(activity, activity);
    }

    public static void injectView(Object object, View view) {
        ViewInject proxyActivity = findProxyActivity(object);
        proxyActivity.inject(object, view);
    }

    private static ViewInject findProxyActivity(Object activity) {
        try {
            Class clazz = activity.getClass();
            Class injectorClazz = Class.forName(clazz.getName() + SUFFIX);
            return (ViewInject) injectorClazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        throw new RuntimeException(String.format("can not find %s , something when compiler.", activity.getClass().getSimpleName() + SUFFIX));
    }
}

使用方法如下:

  @DeBindView(R.id.tv_text)
    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_annotation);
        ViewInjector.injectView(this);
    }

以上就是简单的使用编译时注解,完成时间绑定,详细代码请下载查看,包含annotationapi ,javalib 两个module,其中annotationapi 依赖javalib 。使用的时候导入module 主module app只需要依赖annotationapi就可以了
下载地址:点击

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring容器是一个轻量级的容器,它可以管理对象及其依赖关系,并将它们组成一个整体,使得应用程序更易于开发和维护。Spring容器提供了两种类型的容器:BeanFactory和ApplicationContext。BeanFactory是Spring的最基本容器,它提供了基本的依赖注入功能,而ApplicationContext则是BeanFactory的扩展,提供了更多的功能,比如事件传播、国际化等。 Spring容器的基本使用可以分为以下几个步骤: 1. 定义bean:在Spring容器中,所有的对象都被视为bean。你需要在配置文件中定义这些bean,指定它们的类、属性等信息。 2. 配置bean:配置bean就是指定bean的属性和依赖关系。Spring提供了多种方式来配置bean,比如XML配置、注解配置、Java配置等。 3. 加载容器:Spring容器可以通过ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、AnnotationConfigApplicationContext等方式进行加载。 4. 获取bean:一旦容器加载完成,就可以从容器中获取bean了。可以通过getBean()方法或者@Autowired注解来获取bean。 5. 使用bean:获取bean之后,就可以使用它们了。可以调用bean的方法,或者将bean注入到其他对象中。 下面是一个简单的示例,演示了如何使用Spring容器: 1. 定义一个HelloWorld类 ```java public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage(){ System.out.println("Your Message : " + message); } } ``` 2. 在配置文件中定义bean ```xml <bean id="helloWorld" class="com.example.HelloWorld"> <property name="message" value="Hello World!"/> </bean> ``` 3. 加载容器并获取bean ```java public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld obj = (HelloWorld) context.getBean("helloWorld"); obj.getMessage(); } } ``` 以上就是Spring容器的基本使用方法。通过这些步骤,我们可以在应用程序中轻松地管理和使用对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值