面試官:你天天用 Lombok,說說它什么原理?我竟然答不上來…
點(diǎn)擊上方“碼農(nóng)突圍”,馬上關(guān)注 這里是碼農(nóng)充電第一站,回復(fù)“666”,獲取一份專屬大禮包 真愛,請(qǐng)?jiān)O(shè)置“星標(biāo)”或點(diǎn)個(gè)“在看”
鏈接:https://juejin.cn/post/6844904072789622792
Lombok如何使用
compile?("org.projectlombok:lombok:1.16.6")
功能
@Data
public?class?TestLombok?{
????private?String?name;
????private?Integer?age;
????public?static?void?main(String[]?args)?{
????????TestLombok?testLombok?=?new?TestLombok();
????????testLombok.setAge(12);
????????testLombok.setName("zs");
????}
}
Data注解,在沒有寫get、set方法的時(shí)候也能夠使用其get、set方法。我們看它編譯過后的class文件,可以看到它給我們自動(dòng)生成了get、set方法。public?class?TestLombok?{
????private?String?name;
????private?Integer?age;
????public?static?void?main(String[]?args)?{
????????TestLombok?testLombok?=?new?TestLombok();
????????testLombok.setAge(12);
????????testLombok.setName("zs");
????}
????public?TestLombok()?{
????}
????public?String?getName()?{
????????return?this.name;
????}
????public?Integer?getAge()?{
????????return?this.age;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?void?setAge(Integer?age)?{
????????this.age?=?age;
????}
}
Spring框架中@Controller、@Service等等這類注解都是運(yùn)行時(shí)注解,運(yùn)行時(shí)注解大部分都是通過反射來實(shí)現(xiàn)的。而Lombok是使用編譯時(shí)注解實(shí)現(xiàn)的。那么編譯時(shí)注解是什么呢?編譯時(shí)注解
注解(也被成為元數(shù)據(jù))為我們?cè)诖a中添加信息提供了一種形式化的方法,使我們可以在稍后某個(gè)時(shí)刻非常方便地使用這些數(shù)據(jù)。——————摘自《Thinking in Java》
編譯期:Java語言的編譯期是一段不確定的操作過程,因?yàn)樗赡苁菍?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">*.java文件轉(zhuǎn)化成 *.class文件的過程;也可能是指將字節(jié)碼轉(zhuǎn)變成機(jī)器碼的過程;還可能是直接將*.java編譯成本地機(jī)器代碼的過程運(yùn)行期:從JVM加載字節(jié)碼文件到內(nèi)存中,到最后使用完畢以后卸載的過程都屬于運(yùn)行期的范疇。
注解處理工具apt
注解處理工具apt(Annotation Processing Tool),這是Sun為了幫助注解的處理過程而提供的工具,apt被設(shè)計(jì)為操作Java源文件,而不是編譯后的類。
Lombok不就是在我們?cè)械奈募行略隽艘恍┬畔幔课以诤竺鏁?huì)有詳細(xì)的解釋,這里簡單介紹一下,其實(shí)Lombok是修改了Java中的抽象語法樹AST才做到了修改其原有類的信息。APT工具生成一個(gè)class文件,然后我們?cè)僬fLombok是如何修改已存在的類中的屬性的。定義注解
@Retention(RetentionPolicy.SOURCE)?//?注解只在源碼中保留
@Target(ElementType.TYPE)?//?用于修飾類
public?@interface?GeneratePrint?{
????String?value();
}
Retention注解上面有一個(gè)屬性value,它是RetentionPolicy類型的枚舉類,RetentionPolicy枚舉類中有三個(gè)值。最新面試題整理好了,點(diǎn)擊Java面試庫小程序在線刷題。public?enum?RetentionPolicy?{
????SOURCE,
????CLASS,
????RUNTIME
}
SOURCE修飾的注解:修飾的注解,表示注解的信息會(huì)被編譯器拋棄,不會(huì)留在class文件中,注解的信息只會(huì)留在源文件中CLASS修飾的注解:表示注解的信息被保留在class文件(字節(jié)碼文件)中當(dāng)程序編譯時(shí),但不會(huì)被虛擬機(jī)讀取在運(yùn)行的時(shí)候RUNTIME修飾的注解:表示注解的信息被保留在class文件(字節(jié)碼文件)中當(dāng)程序編譯時(shí),會(huì)被虛擬機(jī)保留在運(yùn)行時(shí)。所以它能夠通過反射調(diào)用,所以正常運(yùn)行時(shí)注解都是使用的這個(gè)參數(shù)
Target注解上面也有個(gè)屬性value,它是ElementType類型的枚舉。是用來修飾此注解作用在哪的。public?enum?ElementType?{
????TYPE,
????FIELD,
????METHOD,
????PARAMETER,
????CONSTRUCTOR,
????LOCAL_VARIABLE,
????ANNOTATION_TYPE,
????PACKAGE,
????TYPE_PARAMETER,
????TYPE_USE
}
定義注解處理器
AbstractProcessor類。繼承完以后基本的框架類型如下。@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("aboutjava.annotion.MyGetter")
public?class?MyGetterProcessor?extends?AbstractProcessor?{
????@Override
????public?synchronized?void?init(ProcessingEnvironment?processingEnv)?{
????super.init(processingEnv);
????}
????@Override
????public?boolean?process(Set?extends?TypeElement>?annotations,?RoundEnvironment?roundEnv)?{
????????return?true;
????}
}
@SupportedSourceVersion:表示所支持的Java版本@SupportedAnnotationTypes:表示該處理器要處理的注解
init方法:主要是獲得編譯時(shí)期的一些環(huán)境信息 process方法:在編譯時(shí),編譯器執(zhí)行的方法。也就是我們寫具體邏輯的地方
AbstractProcessor類來實(shí)現(xiàn)在編譯時(shí)生成類,所以我們?cè)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 179, 120);">process方法中書寫我們生成類的代碼。關(guān)注Java核心技術(shù),推送更多 Java 干貨!
@Override
public?boolean?process(Set?extends?TypeElement>?annotations,?RoundEnvironment?roundEnv)?{
????StringBuilder?builder?=?new?StringBuilder()
????????????.append("package?aboutjava.annotion;\n\n")
????????????.append("public?class?GeneratedClass?{\n\n")?//?open?class
????????????.append("\tpublic?String?getMessage()?{\n")?//?open?method
????????????.append("\t\treturn?\"");
????//?for?each?javax.lang.model.element.Element?annotated?with?the?CustomAnnotation
????for?(Element?element?:?roundEnv.getElementsAnnotatedWith(MyGetter.class))?{
????????String?objectType?=?element.getSimpleName().toString();
????????//?this?is?appending?to?the?return?statement
????????builder.append(objectType).append("?says?hello!\\n");
????}
????builder.append("\";\n")?//?end?return
????????????.append("\t}\n")?//?close?method
????????????.append("}\n");?//?close?class
????try?{?//?write?the?file
????????JavaFileObject?source?=?processingEnv.getFiler().createSourceFile("aboutjava.annotion.GeneratedClass");
????????Writer?writer?=?source.openWriter();
????????writer.write(builder.toString());
????????writer.flush();
????????writer.close();
????}?catch?(IOException?e)?{
????????//?Note:?calling?e.printStackTrace()?will?print?IO?errors
????????//?that?occur?from?the?file?already?existing?after?its?first?run,?this?is?normal
????}
????return?true;
}
定義使用注解的類(測(cè)試類)
@MyGetter
public?class?TestAno?{
????public?static?void?main(String[]?args)?{
????????System.out.printf("1");
????}
}
MyGetter類是注解類沒錯(cuò),而MyGetterProcessor是注解類的處理器,那么我們?cè)诰幾gTestAnoJava文件的時(shí)候就會(huì)觸發(fā)處理器。因此這兩個(gè)類是無法一起編譯的。aboutjava
????--?annotion
????????--?MyGetter.java
????????--?MyGetterProcessor.java
????????--?TestAno.java
javac?aboutjava/annotion/MyGett*
processor參數(shù),用來指定相關(guān)的注解處理類。javac?-processor?aboutjava.annotion.MyGetterProcessor?aboutjava/annotion/TestAno.java

(完)
碼農(nóng)突圍資料鏈接
1、臥槽!字節(jié)跳動(dòng)《算法中文手冊(cè)》火了,完整版 PDF 開放下載!
2、計(jì)算機(jī)基礎(chǔ)知識(shí)總結(jié)與操作系統(tǒng) PDF 下載
3、艾瑪,終于來了!《LeetCode Java版題解》.PDF
4、Github 10K+,《LeetCode刷題C/C++版答案》出爐.PDF歡迎添加魚哥個(gè)人微信:smartfish2020,進(jìn)粉絲群或圍觀朋友圈
評(píng)論
圖片
表情

