亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入淺析Java注解框架

 更新時(shí)間:2016年05月24日 16:56:46   作者:Joyfulmath  
這篇文章主要介紹了深入淺析Java注解框架的相關(guān)資料,介紹的非常詳細(xì),具有參考價(jià)值,需要的朋友參考下吧

我們經(jīng)常會(huì)在java代碼里面看到:“@Override”,“@Target”等等樣子的東西,這些是什么?

在java里面它們是“注解”。

下面是百度百科的解釋?zhuān)簀ava.lang.annotation.Retention可以在您定義Annotation型態(tài)時(shí),指示編譯器如何對(duì)待您的自定義 Annotation,預(yù)設(shè)上編譯器會(huì)將Annotation資訊留在class檔案中,但不被虛擬機(jī)器讀取,而僅用于編譯器或工具程式運(yùn)行時(shí)提供資訊。

也就是說(shuō),注解是建立在class文件基礎(chǔ)上的東西,同C語(yǔ)言的宏有異曲同工的效果。

class文件里面根本看不到注解的痕跡。

注解的基礎(chǔ)就是反射。所以注解可以理解為java特有的一種概念。

1.元注解

在java.lang.annotation包里面,已經(jīng)定義了4種annotation的“原語(yǔ)”。

1).@Target,用于明確被修飾的類(lèi)型:(方法,字段,類(lèi),接口等等)  

2).@Retention,描述anntation存在的為止:

RetentionPolicy.RUNTIME 注解會(huì)在class字節(jié)碼文件中存在,在運(yùn)行時(shí)可以通過(guò)反射獲取到

RetentionPolicy.CLASS 默認(rèn)的保留策略,注解會(huì)在class字節(jié)碼文件中存在,但運(yùn)行時(shí)無(wú)法獲得

RetentionPolicy.SOURCE 注解僅存在于源碼中,在class字節(jié)碼文件中不包含

3).@Documented,默認(rèn)情況下,注解不會(huì)在javadoc中記錄,但是可以通過(guò)這個(gè)注解來(lái)表明這個(gè)注解需要被記錄。

4).@Inherited 元注解是一個(gè)標(biāo)記注解,@Inherited闡述了某個(gè)被標(biāo)注的類(lèi)型是被繼承的。

如果一個(gè)使用了@Inherited修飾的annotation類(lèi)型被用于一個(gè)class,則這個(gè)annotation將被用于該class的子類(lèi)。

2.自定義注解

package com.joyfulmath.jvmexample.annnotaion;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author deman.lu
* @version on 2016-05-23 13:36
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitName {
String value() default "";
} 

首先,一個(gè)注解一般需要2個(gè)元注解修飾:

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

具體作用上面已解釋。

所有的注解都會(huì)有一個(gè)類(lèi)似于“func”的部分。這個(gè)可以理解為注解的參數(shù)。

package com.joyfulmath.jvmexample.annnotaion;
import com.joyfulmath.jvmexample.TraceLog;
/**
* @author deman.lu
* @version on 2016-05-23 13:37
*/
public class Apple {
@FruitName("Apple")
String appleName;
public void displayAppleName()
{
TraceLog.i(appleName);
}
}

這段代碼的log:

05-23 13:39:38.780 26792-26792/com.joyfulmath.jvmexample I/Apple: displayAppleName: null [at (Apple.java:16)]

沒(méi)有賦值成功,為什么?應(yīng)為注解的“Apple”到底怎么賦值該filed,目前編譯器還不知道則怎么做呢。

3.注解處理器

我們還需要一個(gè)處理器來(lái)解釋 注解到底是怎樣工作的,不然就跟注釋差不多了。

通過(guò)反射的方式,可以獲取注解的內(nèi)容:

package com.joyfulmath.jvmexample.annnotaion;
import com.joyfulmath.jvmexample.TraceLog;
import java.lang.reflect.Field;
/**
* @author deman.lu
* @version on 2016-05-23 14:08
*/
public class FruitInfoUtils {
public static void getFruitInfo(Class<?> clazz)
{
String fruitNameStr = "";
Field[] fields = clazz.getDeclaredFields();
for(Field field:fields)
{
if(field.isAnnotationPresent(FruitName.class))
{
FruitName fruitName = field.getAnnotation(FruitName.class);
fruitNameStr = fruitName.value();
TraceLog.i(fruitNameStr);
}
}
}
}

這是注解的一般用法。

android注解框架解析

從上面可以看到,注解框架的使用,本質(zhì)上還是要用到反射。

但是我如果用反射的功能在使用注解框架,那么,我還不如直接使用它,反而簡(jiǎn)單。

如果有一種機(jī)制,可以避免寫(xiě)大量重復(fù)的相似代碼,尤其在android開(kāi)發(fā)的時(shí)候,大量的findviewbyid & onClick等事件相應(yīng)。

代碼的模式是一致的,但是代碼又各不相同,這個(gè)時(shí)候,使用注解框架可以大量節(jié)省開(kāi)發(fā)時(shí)間,當(dāng)然相應(yīng)的會(huì)增加其他的開(kāi)銷(xiāo)。

以下就是一個(gè)使用butterknife的例子:

@BindString(R.string.login_error)
String loginErrorMessage;

看上去很簡(jiǎn)單,就是把字符串賦一個(gè)string res對(duì)應(yīng)的初值。這樣寫(xiě)可以節(jié)省一些時(shí)間。當(dāng)然這只是一個(gè)例子,

如果大量使用其他的注解,可以節(jié)省很大一部分的開(kāi)發(fā)時(shí)間。

我們下面來(lái)看看怎么實(shí)現(xiàn)的:

package butterknife;
import android.support.annotation.StringRes;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.CLASS;
/**
* Bind a field to the specified string resource ID.
* <pre><code>
* {@literal @}BindString(R.string.username_error) String usernameErrorText;
* </code></pre>
*/
@Retention(CLASS) @Target(FIELD)
public @interface BindString {
/** String resource ID to which the field will be bound. */
@StringRes int value();
}

BindString,只有一個(gè)參數(shù),value,也就是賦值為@StringRes.

同上,上面是注解定義和使用的地方,但是真正解釋注解的地方如下:ButterKnifeProcessor

private Map<TypeElement, BindingClass> findAndParseTargets(RoundEnvironment env)

這個(gè)函數(shù),截取部分代碼:

// Process each @BindString element.
for (Element element : env.getElementsAnnotatedWith(BindString.class)) {
if (!SuperficialValidation.validateElement(element)) continue;
try {
parseResourceString(element, targetClassMap, erasedTargetNames);
} catch (Exception e) {
logParsingError(element, BindString.class, e);
}
}

找到所有BindString注解的元素,然后開(kāi)始分析:

private void parseResourceString(Element element, Map<TypeElement, BindingClass> targetClassMap,
Set<TypeElement> erasedTargetNames) {
boolean hasError = false;
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// Verify that the target type is String.
if (!STRING_TYPE.equals(element.asType().toString())) {
error(element, "@%s field type must be 'String'. (%s.%s)",
BindString.class.getSimpleName(), enclosingElement.getQualifiedName(),
element.getSimpleName());
hasError = true;
}
// Verify common generated code restrictions.
hasError |= isInaccessibleViaGeneratedCode(BindString.class, "fields", element);
hasError |= isBindingInWrongPackage(BindString.class, element);
if (hasError) {
return;
}
// Assemble information on the field.
String name = element.getSimpleName().toString();
int id = element.getAnnotation(BindString.class).value();
BindingClass bindingClass = getOrCreateTargetClass(targetClassMap, enclosingElement);
FieldResourceBinding binding = new FieldResourceBinding(id, name, "getString", false);
bindingClass.addResource(binding);
erasedTargetNames.add(enclosingElement);
}

首先驗(yàn)證element是不是string類(lèi)型。

// Assemble information on the field.
String name = element.getSimpleName().toString();
int id = element.getAnnotation(BindString.class).value(); 

獲取field的name,以及 string id。

最終

Map<TypeElement, BindingClass> targetClassMap

元素和注解描述,已map的方式一一對(duì)應(yīng)存放。

@Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
Map<TypeElement, BindingClass> targetClassMap = findAndParseTargets(env);
for (Map.Entry<TypeElement, BindingClass> entry : targetClassMap.entrySet()) {
TypeElement typeElement = entry.getKey();
BindingClass bindingClass = entry.getValue();
try {
bindingClass.brewJava().writeTo(filer);
} catch (IOException e) {
error(typeElement, "Unable to write view binder for type %s: %s", typeElement,
e.getMessage());
}
}
return true;
}

這就是注解框架啟動(dòng)的地方,一個(gè)獨(dú)立的進(jìn)程。具體細(xì)節(jié)本文不研究,只需清除,這里是框架驅(qū)動(dòng)的地方。

從上面的信息已經(jīng)清除,所有的注解信息都存放在targetClassMap 里面。

上面標(biāo)紅的代碼,應(yīng)該是注解框架的核心之處。

自從Java SE5開(kāi)始,Java就引入了apt工具,可以對(duì)注解進(jìn)行預(yù)處理,Java SE6,更是支持?jǐn)U展注解處理器,

并在編譯時(shí)多趟處理,我們可以使用自定義注解處理器,在Java編譯時(shí),根據(jù)規(guī)則,生成新的Java代碼。

JavaFile brewJava() {
TypeSpec.Builder result = TypeSpec.classBuilder(generatedClassName)
.addModifiers(PUBLIC);
if (isFinal) {
result.addModifiers(Modifier.FINAL);
} else {
result.addTypeVariable(TypeVariableName.get("T", targetTypeName));
}
TypeName targetType = isFinal ? targetTypeName : TypeVariableName.get("T");
if (hasParentBinding()) {
result.superclass(ParameterizedTypeName.get(parentBinding.generatedClassName, targetType));
} else {
result.addSuperinterface(ParameterizedTypeName.get(VIEW_BINDER, targetType));
}
result.addMethod(createBindMethod(targetType));
if (isGeneratingUnbinder()) {
result.addType(createUnbinderClass(targetType));
} else if (!isFinal) {
result.addMethod(createBindToTargetMethod());
}
return JavaFile.builder(generatedClassName.packageName(), result.build())
.addFileComment("Generated code from Butter Knife. Do not modify!")
.build();
}

這段話的關(guān)鍵是會(huì)create一個(gè)新文件。

然后把相關(guān)內(nèi)容寫(xiě)入。

相關(guān)文章

  • Java并發(fā)編程之線程創(chuàng)建介紹

    Java并發(fā)編程之線程創(chuàng)建介紹

    這篇文章主要介紹了Java并發(fā)編程之線程創(chuàng)建,進(jìn)程是代碼在數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,線程則是一個(gè)實(shí)體,一個(gè)進(jìn)程中至少有一個(gè)線程,下文更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-04-04
  • 詳談Springfox與swagger的整合使用

    詳談Springfox與swagger的整合使用

    下面小編就為大家?guī)?lái)一篇詳談Springfox與swagger的整合使用。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 使用Spring注入Hibernate驗(yàn)證框架

    使用Spring注入Hibernate驗(yàn)證框架

    這篇文章主要介紹了使用Spring注入Hibernate驗(yàn)證框架方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Spring中的@ConditionalOnProperty注解詳解

    Spring中的@ConditionalOnProperty注解詳解

    這篇文章主要介紹了Spring中的@ConditionalOnProperty注解詳解,常見(jiàn)的@Conditionalxxx開(kāi)頭的注解我們稱(chēng)之為條件注解,常見(jiàn)的條件注解有,簡(jiǎn)單來(lái)講,一般是在配置類(lèi)上或者是@Bean修飾的方法上,添加此注解表示一個(gè)類(lèi)是否要被Spring上下文加載,需要的朋友可以參考下
    2024-01-01
  • SpringMVC如何自定義響應(yīng)的HTTP狀態(tài)碼

    SpringMVC如何自定義響應(yīng)的HTTP狀態(tài)碼

    這篇文章主要介紹了SpringMVC如何自定義響應(yīng)的HTTP狀態(tài)碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 淺談圖片上傳利用request.getInputStream()獲取文件流時(shí)遇到的問(wèn)題

    淺談圖片上傳利用request.getInputStream()獲取文件流時(shí)遇到的問(wèn)題

    下面小編就為大家?guī)?lái)一篇淺談圖片上傳利用request.getInputStream()獲取文件流時(shí)遇到的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • 使用c3p0連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)增刪改查

    使用c3p0連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)增刪改查

    這篇文章主要為大家詳細(xì)介紹了使用c3p0連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)增刪改查,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 基于Java Gradle復(fù)制項(xiàng)目模塊過(guò)程圖解

    基于Java Gradle復(fù)制項(xiàng)目模塊過(guò)程圖解

    這篇文章主要介紹了基于Java Gradle復(fù)制項(xiàng)目模塊過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 使用Mock進(jìn)行業(yè)務(wù)邏輯層Service測(cè)試詳解

    使用Mock進(jìn)行業(yè)務(wù)邏輯層Service測(cè)試詳解

    這篇文章主要介紹了使用Mock進(jìn)行業(yè)務(wù)邏輯層Service測(cè)試詳解,mock是一種模擬對(duì)象的技術(shù),用于在測(cè)試過(guò)程中替代真實(shí)的對(duì)象,通過(guò)mock,我們可以控制被模擬對(duì)象的行為和返回值,以便進(jìn)行更加精確的測(cè)試,需要的朋友可以參考下
    2023-08-08
  • 關(guān)于request.getRequestDispatcher().forward()的妙用及DispatcherType對(duì)Filter配置的影響

    關(guān)于request.getRequestDispatcher().forward()的妙用及DispatcherType

    這篇文章主要介紹了關(guān)于request.getRequestDispatcher().forward()的妙用及DispatcherType對(duì)Filter配置的影響,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評(píng)論