Java AbstractProcessor实现自定义ButterKnife

ButterKnife源码探究(附实现自定义注解处理器) Map集合的key为一个TypeElement类型(比如我们在MainActivity中定义了注解,那么比会有一个TypeElement的对象对应MainActivity),表示被注解的类,value为一个BindingSet对象,里面有待生成的Java类所需的所有信息,包括类名包名、绑定的控件(比如我们生成MainActivity对应的绑定类MainActivity_ViewBinding所需要的所有信息)。可以看到BindeView注解保留到class文件中,并且是修饰成员变量的。 阅读详情

在上一节中Java注解及自定义注解处理器,主要是说明了Java注解的基本用法以及通过反射在JVM运行时实现Java的注解处理器,同时也说明了通过反射实现注解处理器会对代码的运行性能有一定影响。

所以这里主要说明另一种方式,也就是通过AbstractProcessor在Java编译时生成代码的方式实现注解处理器。

AbstractProcessor介绍

AbstractProcessor,是一个抽象类,该类实现了接口Processor。
抽象类AbstractProcessor以及接口Processor都是位于包javax.annotation.processing中。该接口中定义的所有类、接口都是与实现注解处理器相关的。如下图所示:
这里写图片描述

这里主要说说AbstractProcessor类中各方法的用法。
这里写图片描述

init

void init(ProcessingEnvironment processingEnv) ,该方法主要用于一些初始化的操作,通过该方法的参数ProcessingEnvironment可以获取一些列有用的工具类。

ProcessingEnvironment源码如下:

public interface ProcessingEnvironment {

        /**
         * 返回用来在元素上进行操作的某些实用工具方法的实现。<br>
         *
         * Elements是一个工具类,可以处理相关Element(包括ExecutableElement, PackageElement, TypeElement, TypeParameterElement, VariableElement)
         */
        Elements getElementUtils();

        /**
         * 返回用来报告错误、警报和其他通知的 Messager。
         */
        Messager getMessager();

        /**
         *  用来创建新源、类或辅助文件的 Filer。
         */
        Filer getFiler();

        /**
         *  返回用来在类型上进行操作的某些实用工具方法的实现。
         */
        Types getTypeUtils();

        // 返回任何生成的源和类文件应该符合的源版本。
        SourceVersion getSourceVersion();

        // 返回当前语言环境;如果没有有效的语言环境,则返回 null。
        Locale getLocale();

        // 返回传递给注释处理工具的特定于 processor 的选项
        Map<String, String> getOptions();
    }

getSupportedSourceVersion

返回此注释 Processor 支持的最新的源版本,该方法可以通过注解@SupportedSourceVersion指定。

@Override
public SourceVersion getSupportedSourceVersion() {
  return SourceVersion.latestSupported();
}

getSupportedAnnotationTypes

返回此 Processor 支持的注释类型的名称。结果元素可能是某一受支持注释类型的规范(完全限定)名称。它也可能是 ” name.” 形式的名称,表示所有以 ” name.” 开头的规范名称的注释类型集合。最后,自身表示所有注释类型的集合,包括空集。注意,Processor 不应声明 “*”,除非它实际处理了所有文件;声明不必要的注释可能导致在某些环境中的性能下降。

process

注解处理器的核心方法,处理具体的注解,这个将在下面的自定义注解中详细说明该方法应该如何使用。

其中,getSupportedSourceVersion和getSupportedAnnotationTypes也可以通过给注解处理器添加注解指定具体值。
如下:

@SupportedOptions()
@SupportedAnnotationTypes()
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class ButterKnifeProcessor extends AbstractProcessor {
    // 省略具体代码
}

自定义ButterKnife

在Android中,ButterKnife是一个通过注解实现依赖注入的框架,所以这里也通过实现一个简单的ButterKnife框架,熟悉通过 AbstractProcessor实现注解处理器的过程。

首先,需要创建两个Java库butterknife-annotations和butterknife-compiler以及一个android库butterknife

  • butterknife-annotations,用于声明具体的注解的,如BindView、OnClick等)。主要供butterknife-compiler和butterknife库引用
  • butterknife-compiler,用于声明自定义AbstractProcessor,在编译时生成具体的Java文件。
  • butterknife,这个就是具体android项目中需要引用的库,主要实现具体依赖注入的功能。

这里有两个问题需要说明:
为什么需要创建Java库? 创建Java库是因为在使用自定义AbstractProcessor需要使用到javax包中的相关类和接口,这个在android库中并不存在,所以需要使用到Java库。

为什么需要创建两个库? 因为自定义AbstractProcessor的作用是在编译时生成相关的java源文件的,在程序中最后需要的是他生成的Java文件,最后打包进apk也是他生成的文件,butterknife-compiler本身是不需要打包的。
但是在butterknife-compiler和butterknife中需要对具体的注解类进行操作,需要引用butterknife-annotations库,所以将具体的注解放在一个库butterknife-annotations中便于引用。

butterknife-annotations

在这个库中主要用于声明具体的注解的,这里通过定义一个@BindView注解作为示例,如下

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface BindView {

    int value();
}

butterknife-compiler

在butterknife-compiler库中,主要的功能就是自定义AbstractProcessor,在编译时生成具体的Java文件实现依赖注入功能。因为该注解处理器需要使用到指定注解,所以该库需要依赖butterknife-annotations。

关于AbstractProcessor类中个各个方法在上面已经提到过,这里主要说一下process方法的具体功能。

在process方法中我们主要有两个功能需要完成:

  • 获取同一个类中的所有指定注解修饰的Element;
    在process方法中,有一个参数RoundEnvironment,通过该参数可以通过遍历获取代码中所有通过指定注解(这里只@BindeView)修饰的Element对象。通过Element对象可以获取字段名称,字段类型以及注解元素的值。
  • 创建Java文件;
    将同一个类中通过指定注解修饰的所有Element在同一个Java文件中实现初始化,这样做的目的是让在最终依赖注入时便于操作。

对于生成Java文件需要使用到开源库javapoet,这是square专门开发的用于辅助生成Java文件的库,关于该库的用法这里不做过多说明。

下面是自定义AbstractProcessor中的具体逻辑:

package com.zhangke.compiler;

import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import com.zhangke.annotations.BindView;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

@AutoService(Processor.class)
public class ButterKnifeProcessor extends AbstractProcessor {

    private Messager messager;
    private Elements elementUtils;
    private Filer filer;
    private Types typeUtils;

    /**
     * `
     * 初始化操作
     *
     * @param processingEnvironment
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        typeUtils = processingEnvironment.getTypeUtils();
        elementUtils = processingEnvironment.getElementUtils();
        filer = processingEnvironment.getFiler();
        messager = processingEnvironment.getMessager();
    }

    /**
     * 返回此Porcessor可以处理的注解操作
     *
     * @return
     */
    @Override
    public Set<String> getSupportedOptions() {
        return super.getSupportedOptions();
    }

    /**
     * 返回此注释 Processor 支持的最新的源版本
     * <p>
     * 该方法可以通过注解@SupportedSourceVersion指定
     *
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    /**
     * 返回此 Processor 支持的注释类型的名称。结果元素可能是某一受支持注释类型的规范(完全限定)名称。它也可能是 " name.*" 形式的名称,表示所有以 " name." 开头的规范名称的注释类型集合。最后, "*" 自身表示所有注释类型的集合,包括空集。注意,Processor 不应声明 "*",除非它实际处理了所有文件;声明不必要的注释可能导致在某些环境中的性能下降。
     * <p>
     * 该方法可以通过注解@SupportedSourceVersion指定
     *
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> set = new LinkedHashSet<>();
        set.add(BindView.class.getCanonicalName());
        return set;
    }


    /**
     * 注解处理器的核心方法,处理具体的注解
     *
     * @param set
     * @param roundEnvironment
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        // 通过roundEnvironment扫描所有的类文件,获取所有存在指定注解的字段
        Map<TypeElement, List<FieldViewBinding>> targetMap = getTargetMap(roundEnvironment);


        createJavaFile(targetMap.entrySet());
        return false;
    }

    /**
     * 获取所有存在注解的类
     *
     * @param roundEnvironment
     * @return
     */
    private Map<TypeElement, List<FieldViewBinding>> getTargetMap(RoundEnvironment roundEnvironment) {
        /**
         * 键:TypeElement,指定Activity;
         * 值:List<FieldViewBinding>,activiyt中所有的注解修饰的字段
         */
        Map<TypeElement, List<FieldViewBinding>> targetMap = new HashMap<>();

        // 1、获取代码中所有使用@BindView注解修饰的字段
        Set<? extends Element> annotatedElements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
        for (Element element : annotatedElements) {
            // 获取字段名称 (textView)
            String fieldName = element.getSimpleName().toString();
            // 获取字段类型 (android.widget.TextView)
            TypeMirror fieldType = element.asType();
            // 获取注解元素的值 (R.id.textView)
            int viewId = element.getAnnotation(BindView.class).value();

            // 获取声明element的全限定类名 (com.zhangke.simplifybutterknife.MainActivity)
            TypeElement typeElement = (TypeElement) element.getEnclosingElement();
            List<FieldViewBinding> list = targetMap.get(typeElement);
            if (list == null) {
                list = new ArrayList<>();
                targetMap.put(typeElement, list);
            }

            list.add(new FieldViewBinding(fieldName, fieldType, viewId));

        }

        return targetMap;
    }

    /**
     * 创建Java文件
     * @param entries
     */
    private void createJavaFile(Set<Map.Entry<TypeElement, List<FieldViewBinding>>> entries) {
        for (Map.Entry<TypeElement, List<FieldViewBinding>> entry : entries) {
            TypeElement typeElement = entry.getKey();
            List<FieldViewBinding> list = entry.getValue();
            if (list == null || list.size() == 0) {
                continue;
            }


            // 获取包名
            String packageName = elementUtils.getPackageOf(typeElement).getQualifiedName().toString();
            // 根据旧Java类名创建新的Java文件
            String className = typeElement.getQualifiedName().toString().substring(packageName.length() + 1);
            String newClassName = className + "_ViewBinding";


            MethodSpec.Builder methodBuilder = MethodSpec.constructorBuilder()
                    .addModifiers(Modifier.PUBLIC)
                    .addParameter(ClassName.bestGuess(className), "target");
            for (FieldViewBinding fieldViewBinding : list) {
                String packageNameString = fieldViewBinding.getFieldType().toString();
                ClassName viewClass = ClassName.bestGuess(packageNameString);
                methodBuilder.addStatement
                        ("target.$L=($T)target.findViewById($L)", fieldViewBinding.getFieldName()
                                , viewClass, fieldViewBinding.getViewId());
            }


            TypeSpec typeBuilder = TypeSpec.classBuilder(newClassName)
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .addMethod(methodBuilder.build())
                    .build();


            JavaFile javaFile = JavaFile.builder(packageName, typeBuilder)
                    .addFileComment("Generated code from Butter Knife. Do not modify!")
                    .build();
            try {
                javaFile.writeTo(filer);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

}

注解处理器的配置

在上面基本就实现了一个自定义注解处理器,但是如果想要注解处理器能够在编译器生成代码,这里还需要做一个配置说明,这里有两种配置方法:

第一种方法:
在butterknife-compiler的main目录下创建目录resources/META-INF/services,并在该目录下创建文件javax.annotation.processing.Processor,在该文件中写入注解处理器的全限定类名(这里是com.zhangke.compiler.ButterKnifeProcessor)

如下图:
这里写图片描述

第二种方法:
如何感觉通过上面的方法配置特别麻烦,这里也可以通过google提供的auto-service开源库。通过该方式我们只需要在注解处理器上添加注解@AutoService(Processor.class)即可。

build.gradle配置:

apply plugin: 'java-library'

dependencies {
    compile project(':butterknife-annotations')

    compile 'com.google.auto.service:auto-service:1.0-rc3'
    compile 'com.google.auto:auto-common:0.8'
    compile 'com.squareup:javapoet:1.8.0'
}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"

注解处理器注解:

@AutoService(Processor.class)
public class ButterKnifeProcessor extends AbstractProcessor {
    // 代码省略
}

这样一个注解处理器算是正式完成了,接下来可以看看这个注解处理器是否能生成新的Java文件。

butterknife

butterknife是一个android库工程,该库的作用主要就是完成依赖注入。在该库中会依赖butterknife-annotations,最终在Android项目中我们只需要依赖这个工程即可。

下面看看在butterknife中定义的用于实现依赖注入的工具类:

public class ButterKnife {

    public static void bind(Activity activity) {
        //1、获取全限定类名
        String name = activity.getClass().getName();
        try {
            //2、 根据全限定类名获取通过注解解释器生成的Java类
            Class<?> clazz = Class.forName(name + "_ViewBinding");
            //3、 通过反射获取构造方法并创建实例完成依赖注入
            clazz.getConstructor(activity.getClass()).newInstance(activity);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

使用butterknife完成依赖注入

APT工具

APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码,所以如果想要自定义的注解处理器能够正常运行,必要要通过APT工具来进行处理。
也可以这样理解,只有通过声明APT工具后,程序在编译期间自定义注解解释器才能执行。

这里使用的APT工具是annotationProcessor,这个是Android Gradle插件2.2版本发布后,Android 官方提供了annotationProcessor来代替android-apt的APT工具,关于annotationProcessor和android-apt以及其他一些常见的APT工具这里不做过多解释。

在我们的实例中,需要在项目中也就是在app/build.gradle文件中添加库依赖并且声明APT工具,如下:

dependencies {
    // 省略

    // 添加butterknife依赖
    implementation project(':butterknife')
    annotationProcessor project(':butterknife-compiler')
}

测试

在项目主工程中定义了MainActivity和TwoActivity,在这两个Activity中使用注解@BindView,如下:

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.button)
    Button button;
    @BindView(R.id.textview)
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 通过工具类实现依赖注入
        ButterKnife.bind(this);
        textView.setText("hahhah");
    }
}
public class TwoActivity extends AppCompatActivity {

    @BindView(R.id.imageView)
    ImageView imageView;
    @BindView(R.id.progressBar)
    ProgressBar progressBar;
    @BindView(R.id.checkBox)
    CheckBox checkBox;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_two);
    }
}

通过Android Studio的Rebuild Project,就可以看到在主app工程build/generated/source/apt/debug目录下就已经生成了两个新的Java文件,
如下图:
这里写图片描述

这里可以看看MainActivity_ViewBinding类中的具体内容,发现在该文件中为MainActivity_ViewBinding创建了一个构造方法,该构造方法中需要传入指定的activity,然后在该构造方法中就可以完成button和textView的初始化即findViewByid的过程。

// Generated code from Butter Knife. Do not modify!
package com.zhangke.simplifybutterknife;

import android.widget.Button;
import android.widget.TextView;

public final class MainActivity_ViewBinding {
    public MainActivity_ViewBinding(MainActivity target) {
        target.button = (Button) target.findViewById(2131165219);
        target.textView = (TextView) target.findViewById(2131165305);
    }
}

最后想完成依赖注入,只需要通过工具类ButterKnife的bind方法就可以了,这个在上面MainActivity的源码中可以看到。

这样一个简单的自定义ButterKnife就完成了,因为这个是在看了ButterKnife的源码后进行总结的,其实以上整个流程就是开源项目ButterKnife的基本工作原理。如果有什么不正确的地方,望指正。这里也提供一遍专门讲解ButterKnife的文章:浅析ButterKnife

最后附上项目源码

【java】javac 相关API AbstractProcessor 注解处理器是最重要的拓展处理类了。注意:请确认JAVA的环境变量已经配置成功,并且把tools.jar(它源于此包)加入到自己电脑的环境变量中是一个注解处理工具的集合Element是一个接口,表示一个程序元素,它可以是包、类、方法或者一个变量。表示一个包程序元素。提供对有关包及其成员的信息的访问。表示某个类或接口的方法、构造方法或初始化程序(静态或实例),包括注释类型元素。表示一个类或接口程序元素。提供对有关类型及其成员的信息的访问。注意,枚举类型是一种类,而注解类型是一种接口。 阅读详情

相关推荐

AbstractProcessor小例子

利用annotationProcessor插件在编译期创建Java文件,减少维护成本,提高工作效率

Java-详解javac AbstractProcessor

AbstractProcessor 就是注解处理器 ,在java文件编译成class文件之前,对java文件进行操作,生成代码。(可以参考lombok)这些对象必须在init方法里初始化@SupportedAnnotationTypes(“cc.HelloWorld”) ,“cc.HelloWorld” 是HelloWorld注解的类全名。@SupportedSourceVersion(SourceVersion.RELEASE_7) ,annotation支持版本,向前兼容到JDK7。

yueerba126的博客 1821

TMS-EEG数据预处理:eeglab工具包TESA(一)

b. 自动选择:Tools -> Reject data epochs -> Reject by probability,然后进行Plot -> channel,进行删除。TMS-EEG(经颅磁刺激-脑电图)是一种结合了TMS和EEG记录的技术,这种技术允许研究者在非侵入的情况下探测大脑环路,评估大脑的兴奋性和连通性等皮层特性。对移除脉冲伪迹的数据进行插值:Tools ->TESA -> Interpolate removed data;插值后,画图查看:数据会有数值;

weixin_43604817的博客 1496

编译时注解:AbstractProcessor javapoe自动生成代码

RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃; 源码注解(RetentionPolicy.SOURCE)的生命周期只存在Java源文件这一阶段,是3种生命周期中最短的注解。

行走在路上 3075

Windows下用VS2022编译libcurl全流程(含openssl配置避坑指南)

本文详细介绍了在Windows平台使用Visual Studio 2022编译libcurl库的完整流程,重点解决了集成OpenSSL支持HTTPS功能时的常见配置难题。从环境准备、源码获取、依赖编译到工程配置,提供了清晰的步骤和针对非默认安装路径的避坑指南,帮助开发者高效完成网络库的集成工作。

weixin_29291185的博客 245

AES-GCM加密认证模式:原理、优势与实战应用

在数据安全领域,加密与认证是保障信息机密性和完整性的两大基石。加密确保数据内容不被窃取,而认证则验证数据来源的真实性和传输过程中是否被篡改。传统的加密后认证方案如AES-CBC+HMAC需要串行处理,性能开销较大。GCM(伽罗瓦/计数器模式)作为一种认证加密(AEAD)方案,巧妙地将AES-CTR加密与基于伽罗瓦域的GHASH认证并行结合,实现了单次数据遍历即可同时完成加密和认证,大幅提升了处理效率。其核心价值在于高性能、支持附加认证数据(AAD)以及标准化程度高,广泛应用于TLS协议、无线网络安全和云存储

weixin_28622215的博客 315

Java编译期注解处理器AbstractProcessor使用

AbstractProcessor

wangbingqi的专栏 2253

从零开始用TS开发babylonjs - 本机环境搭建

babylonjs,初始化本地安装,web3d引擎

han3527638的专栏 795

APT 及实现ButterKnife

了解 APT 的相关知识,相信手动实践后你会更容易理解像 Dagger、ARouter、ButterKnife 等这种使用了编译时注解的框架,也更容易理解其内部源码实现,内容如下: 编译时和运行时注解 注解处理器APT AbstractProcessor Element和Elements 自定义注解处理器 使用自定义注解处理器 编译时和运行时注解 1. 译时和运行时注解 先了解一下编译时和运行时的区别: 编译时:指编译器将源代码翻译成机器能够识别的代码的过程,Java 中也就是将 Java 源代码编

怪咖先森的博客 4844

FFmpeg实战:5分钟搞定m3u8视频下载与ts文件合并(附完整命令)

本文详细介绍了如何使用FFmpeg快速下载m3u8视频并合并ts文件为mp4格式。通过简洁的命令行操作,读者可以轻松完成视频处理任务,包括环境准备、链接获取、下载合并及性能优化等实用技巧,特别适合需要高效处理流媒体内容的用户。

weixin_30836759的博客 221

大模型量化技术全解析:从INT8到GPTQ/AWQ,降低部署成本实战指南

模型量化是一种通过降低神经网络权重和激活值的数据精度(如从FP16降至INT8/INT4),从而大幅减少模型内存占用和计算开销的核心模型压缩技术。其原理基于线性变换,将高精度浮点数映射到低精度整数表示,在硬件层面能利用专用低精度计算单元实现显著加速。这项技术的核心价值在于解决了大模型(如千亿参数LLM)部署时面临的高昂显存成本和推理延迟问题,使其能在消费级GPU和边缘设备上高效运行。当前,后训练量化(PTQ)因其无需重新训练的特性成为主流,衍生出GPTQ、AWQ、SmoothQuant等多种方法,广泛应用于

weixin_33804582的博客 631

Android进阶宝典 --- 编译时技术分析

编译时技术分析

qq_33235287的博客 1083

【SpringBoot】1、创建第一个SpringBoot项目

创建SpringBoot项目可以通过两种方式,1、通过访问:https://start.spring.io/,SpringBoot的官方网站进行创建SpringBoot项目;2、通过工具(例如:Idea)创建SpringBoot项目。本次使用开发工具:Idea创建我的第一个SpringBoot项目。 首先,打开我们的Idea开发工具 选择Create New Poject(创建一个新的项目) ...

JACKAL 21万+

Android 自定义注解 AbstractProcessor实现类似ButterKnife

Android 如何使用AbstractProcessorButterKnife例子原理步骤1. 创建两个JAVA依赖库库**viewlink** 为所有注解的代码**viewlinkid-processor**为处理这些注解的自定义AbstractProcessor的代码1. 为什么是JAVA依赖库而不是Android的依赖库?2. 为什么要分成两个库而不是在一个库?2. 定义注解3. 处理注解 -- 核心4. 使用扩展参考 如今很多的第三方库都使用了注解的方式,像ButterKnife,room等。

jiushi1995的博客 1234

PCL 法线定向【2025最新版】

几种法线定向方法的PCL代码实现。

点云侠的博客 2806

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

编译时注解详解及实现ButterKnife

PS:人是一种很乐于接受自我暗示的生物,你给了自己消极暗示,那么你很容易变得颓废,如果你给了自己积极暗示,那么你也会变得积极起来。 今天看一下编译时注解的相关知识,相信手动实践后你会更容易理解像 Dagger、ARouter、ButterKnife 等这种使用了编译时注解的框架,也更容易理解其内部源码实现,内容如下: 编译时和运行时注解 注解处理器APT AbstractProcessor Element和Elements 自定义注解处理器 使用自定义注解处理器 编译时和运行时注解 先了解一下编译时.

躬行之 619

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Java-注解、反射、ButterKnife

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。注解是元数据的一种形式,提供有关于程序但不属于程序本身的数据。注解对它们注解的代码的操作没有直接影响。注解本身没有任何意义,单独的注解就是一种注释,他需要结合其他如反射、插桩等技术才有意义。

喂_balabala 1372

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Java APT实战,现实一个简单的ButterKnife

APT(Annotation Processing Tool)是 Java 提供的一种工具,它能够在编译时期检查源代码中的注解,并根据这些注解生成相应的代码。这一过程有助于自动化编码任务,提升开发效率。在 APT 框架中,是核心类,它规定了注解的处理方式。当 APT 扫描源文件时,它会调用实现了类的process()方法,以便捕获和处理注解。

dm菜鸟编程的专栏 1186

ButterKnife源码分析- 涉及元注解和AbstractProcessor和javapoet

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/dingshuhong_/article/details/84306604 一 、 从调用端分析 为了方便理解我们从最简单最常用的findViewById入手,通常我们只需要...

chuozhenwang2889的博客 141

butterknife源码分析:如何处理注解—反射与注解处理器

有时,我们希望在程序运行或者编译时能获取注解的值,并做一些处理。如何想运行时处理注解,需要通过反射(Reflect);如果是编译时,需要用到注解处理器(AbstractProcessor)。这篇文章结合实例介绍了处理注解的俩种方式。

海的鼻涕的博客 2353

一文带你学完ButterKnife 的源码

ButterKnife 这个开源库火了有一段时间了,刚开始它的实现原理是使用反射实现的,性能较差。再后面的版本中逐渐使用注解+放射实现,性能提高了不少。

m0_56255097的博客 288

Java注解编程终极指南:JavaTutorial教你自定义注解与APT应用

Java注解是现代Java开发中不可或缺的元编程工具,它能在不改变代码逻辑的前提下为程序添加元数据信息。本文将通过JavaTutorial项目的实战案例,带你快速掌握自定义注解的开发技巧与APT(Annotation Processing Tool)技术的实际应用,让你的Java项目开发效率提升300%! ## 📚 注解基础:从内置注解到自定义注解 Java注解本质是一种特殊的接口,通过`@

gitblog_00716的博客 1056

使用注解处理器(Annotation Processor)像butterKnife一样,实现简单的控件初始化

现在很多Android的库都是采用注解的方式,来完成某些功能。仿照butterKnife通过Annotation Processor 实现控件绑,使用注解来完成一个简单的控件初始化。完成这个功能我们就需要知道一个东西,注解处理器。 注解处理器是一个在javac中的,用来编译时扫描和处理的注解的工具。我们可以用自己定义的注解和注册注解处理器来做一些事情。这里我们就需要自定义一个处理器,用来处理i注解并生成一个java文

蜗牛快跑 1883

Android中使用AbstractProcessor在编译时生成代码

Android中使用AbstractProcessor在编译时生成代码 发现这边不错的文章,忍不住转了过来,转自: http://blog.youkuaiyun.com/industriously/article/details/53932425 根据这片文档的简单小demo: https://github.com/AndroidHighQualityCodeStudy/Android_Abstrac...

bjxiaxueliang的CODING小栈 2080

重走JAVA之路(一):复盘ButterKnife-编译时注解

前言 其实一直想写这么个系列,虽然Android开发大部分是基于Java语言的,但是日常开发中基本涉及的都比较简单,当遇到一些疑难杂症的时候,很难去找到根因,本系列就针对一些平常开发比较少涉及的JAVA点,比如、注解、代理、并发等等,希望能帮到一些朋友重新巩固下基础知识。 今天我们主要来说道说道注解中另一种实现方式,编译时注解(CLASS),不同于运行时注解(RUNTIME),大家比较熟悉的需要在...

weixin_34010949的博客 103
上一篇: Java 注解及自定义注解处理器
下一篇: EventBus3.0 源码解析
Kerwin zhang
博客等级 码龄12年 21粉丝 28原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值