Javaコードでは、「@override」、「@target」などのようなものがよくあります。これらは何ですか?
Javaでは、それらは「注釈」です。
以下は、Baidu Encyclopediaの説明です。Java.lang.Annotation.Retentionは、注釈パターンを定義するときにカスタム注釈を処理するようコンパイラに指示できます。コンパイラはクラスアーカイブに注釈情報を残しますが、仮想マシンでは読み取られませんが、コンパイラまたはツールプログラムが実行された場合にのみ情報を提供します。
言い換えれば、注釈はクラスファイルに基づいており、C言語のマクロと同じ効果があります。
クラスファイルには注釈の痕跡はありません。
注釈の基礎は反射です。したがって、注釈はJavaに固有の概念として理解できます。
1。メタノート
Java.lang.Annotationパッケージでは、4つの「プリミティブ」の注釈が定義されています。
1)。@ターゲット、変更されているタイプを明確にするために使用される:(方法、フィールド、クラス、インターフェイスなど)
2)。@保持、年金の存在について説明します。
retentionPolicy.runtimeアノテーションは、クラスバイトコードファイルに存在し、実行時に反射を通じて取得できます。
retentionPolicy.classデフォルトの保持ポリシーでは、アノテーションはクラスバイトコードファイルに存在しますが、実行時には取得できません。
RESENTIONPOLICY.SOURCEアノテーションはソースコードにのみ存在し、クラスBYTECODEファイルには含まれていません。
3)。@文書化されたデフォルトでは、注釈はJavadocで記録されませんが、この注釈は、この注釈を記録する必要があることを示すために使用できます。
4)。 @継承されたメタアノテーションはタグアノテーションであり、@inheritedは、特定の注釈付きタイプが継承されていると説明しています。
@Inherited変更を使用した注釈タイプがクラスに使用される場合、アノテーションはクラスのサブクラスに使用されます。
2。カスタムアノテーション
パッケージcom.joyfulmath.jvmexample.annnotaion; import java.lang.annotation.ElementType; Import java.lang.annotation.Rentention; import java.lang.annotation.retentionPolicy; import java.lang.annotation.target; 13:36*/@ターゲット(elementType.field)@retention(retentionPolicy.runtime)public @interface furtname {string value()default "";}まず第一に、注釈には通常、2つのメタ注釈変更が必要です。
@target(elementtype.field)
@retention(RetentionPolicy.Runtime)
特定の機能は上記で説明されています。
すべての注釈には、「FUNC」に似たセクションがあります。これは、注釈パラメーターとして理解できます。
パッケージcom.joyfulmath.jvmexample.annnotaion;インポートcom.joyfulmath.jvmexample.tracelog;/*** @author deman.lu*@version on 2016-05-23 13:37*/public class apple {@fruitname( "apple")string; public void void displayApplename(){tracelog.i(applename);}}このコードのログ:
05-23 13:39:38.780 26792-26792/com.joyfulmath.jvmexample i/apple:displayapplename:null [at(apple.java:16)]]
割り当てが成功しないのはなぜですか?アノテーション「Apple」にファイルを割り当てる方法は?コンパイラがまだわからない場合は、それを行う方法。
3。注釈プロセッサ
また、注釈がどのように機能するかを説明するプロセッサが必要です。そうでなければ、注釈とほぼ同じになります。
反射を通じて、注釈コンテンツを取得できます。
パッケージcom.joyfulmath.jvmexample.annnotaion;インポートcom.joyfulmath.jvmexample.tracelog; Import java.lang.reflect.field;/*** @author deman.lu* @version on 2016-05-23 14:08*/public vioid etic void estictic fruitnameStr = ""; field [] fields = clazz.getDeclaredfields(); for(field:fields){if(field.isannotationpresent(fruitname.class)){fruitname fruitname = field.getannotation(fruitname.class); fruitnamestname.value(これは、注釈の一般的な使用法です。
Androidアノテーションフレームワーク分析
上記からわかるように、注釈フレームワークの使用には本質的に反射が必要です。
しかし、反射の関数を備えた注釈フレームワークを使用すると、直接使用することもできますが、より簡単です。
メカニズムがある場合、特にAndroid開発中に多くの重複したコードの作成を避けることができます。
コードパターンは一貫していますが、コードは異なります。この時点で、注釈フレームワークを使用すると、多くの開発時間を節約でき、もちろん、それに応じて他のオーバーヘッドが増加します。
バターナイフを使用する例は次のとおりです。
@BindString(R.String.Login_Error)
文字列loginerrormessage;
非常に簡単に思えます。文字列Resに対応する初期値に文字列を割り当てることです。これにより、時間を節約できます。もちろん、これは単なる例です。
他の注釈を大幅に使用する場合は、多くの開発時間を節約できます。
それがどのように実装されているか見てみましょう:
パッケージButterknife; Import android.support.annotation.stringres; import java.lang.annotation; import java.lang.annotation.target; Import static java.lang.annotation.ElementType.field; Import Static Java.lang.Annotation.ententionPolicy.class.class.class.class.class.class.class.class.class.class. <pre> <code>* {@literal @} bindstring(r.string.username_error)string usernameerrortext;* </code> </pre>*/ @retention(class)@target(field)public @interface bindString {/**文字列リソースIDが拘束されます。 */@stringres int値();} BindStringには、値を1つのパラメーター、つまり@stringresに割り当てるだけです。
上記と同じ、上記は注釈が定義され、使用される場所ですが、注釈の本当の説明は次のとおりです。
プライベートマップ<TypeLement、BindingClass> FindAndParsetargets(RundEnvironment env)
この関数は、いくつかのコードを傍受します。
//各@BindString Element.for(要素:env.getElementsAnnotatedWith(bindString.class)){if(!sufficialValidation.validateElement(element))継続; try {parseresourceString(element、targetclassmap、erasedtargetnames); e);}} Bindstringアノテーションのすべての要素を見つけて、分析を開始します。
private void parseresourceString(要素要素、Map <typelement、BindingClass> TargetClassMap、set <TypeLement> eradedTargetNames){boolean hasError = false; typelement enclosingelement =(typelement)ement.getEnclosiseLement(); //ターゲットタイプを確認する(!string_type.equals(element.astype()。toString())){error(element、 "@%sフィールドタイプは 'string'。(%s。%s)"、bindstring.class.getsimplename()、enclosingelement.getQualifiedName()、ementsimplename = rue;制限。haserror| = isinaccessibleviageneratedCode(bindstring.class、 "fields"、element); haserror | = isbindinginwrongpackage(bindstring.class、element); if(haserror){return;} element.getannotation(bindstring.class).value(); bindingclass bindingclass = getorcreateTargetClass(TargetClassMap、EnclosingElement); FieldResourceBinding Binding = New FieldResourceBinding(ID、name、 "getString"、false); bindingddresures(bindergeTargetnames.dddddddddddddddded);まず、要素が文字列型かどうかを確認します。
// field.string name = element.getSimplename()。toString(); int id = element.getAnnotation(bindstring.class).value();
フィールドの名前と文字列IDを取得します。
ファイナル
Map <TypeLement、BindingClass> TargetClassMap
要素と注釈の説明は、マップに1つずつ保存されます。
@Override public booleanプロセス(set <?extends typeLement>要素、roundenvironment env){map <typelement、bindingclass> argetclassmap = findandparsetargets(env); for(map.entry <inentrament、bindingclass> entry:egrateclassmap.entryset() entry.getValue(); try {bindingClass.brewjava()。writeto(filer);} catch(ioException e){exerement、 "ingy for type%s:%s"、typeelement、e.getmessage();}} return true;}これは、アノテーションフレームワークが開始される場所、独立したプロセスです。この記事では、特定の詳細を調査するのではなく、クリアするだけで、これがフレームワーク主導の場所です。
上記の情報から、すべての注釈情報はターゲットクラスマップに保存されます。
上の赤とマークされたコードは、注釈フレームワークの中核である必要があります。
Java SE5以来、JavaはAPTツールを導入しており、注釈を前処理できます。 Java SE6は、拡張注釈プロセッサをサポートしています。
コンピレーション中に複数回処理します。 Javaがコンパイルされたときのルールに従って、カスタム注釈プロセッサを使用して、新しい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(parentbind.generatedClassName、ターゲットタイプ));} if(isgeneratingunbinder()){result.addtype(createunbinderclass(targettype));} else if(!isfinal){result.addmethod(createbindtotargetmethod();} return javafile.builder(generatedclassname.packagename.packagename() result.build())。addfileComment( "バターナイフから生成コード。変更しないでください!")。build();}このパッセージの鍵は、新しいファイルを作成することです。
次に、関連するコンテンツを書きます。