우리는 종종 Java 코드에서 "@override", "@target"등을 본다. 이것들은 무엇입니까?
자바에서는 "주석"입니다.
다음은 Baidu Encyclopedia의 설명입니다. 컴파일러는 클래스 아카이브에 주석 정보를 남겨 두지 만 가상 머신에서 읽지는 않지만 컴파일러 또는 공구 프로그램이 실행될 때만 정보를 제공합니다.
다시 말해, 주석은 클래스 파일을 기반으로하며 C 언어의 매크로와 동일한 영향을 미칩니다.
클래스 파일에는 주석의 흔적이 없습니다.
주석의 기초는 반사입니다. 따라서 주석은 Java에 고유 한 개념으로 이해 될 수 있습니다.
1. 메타 메모
Java.lang.annotation 패키지에서 주석의 4 개의 "프리미티브"가 정의되었습니다.
1).@target, 수정되는 유형을 명확히하기 위해 사용됩니다. (메소드, 필드, 클래스, 인터페이스 등)
2).@retention, annentation의 존재를 설명합니다.
rendentpolicy.runtime 주석은 클래스 바이트 코드 파일에 존재하며 런타임에 반사를 통해 얻을 수 있습니다.
rendentionpolicy.class 기본 유지 정책에 따라 주석은 클래스 바이트 코드 파일에 존재하지만 런타임 중에는 얻을 수 없습니다.
resentpolicy.source 주석은 소스 코드에만 존재하며 클래스 바이트 코드 파일에 포함되지 않습니다.
3).@Documented, 기본적으로 주석은 Javadoc에 기록되지 않지만이 주석은이 주석을 기록해야 함을 나타낼 수 있습니다.
4). @상속 메타 공개는 태그 주석이며 @Inherited는 특정 주석이 달린 유형이 상속되었다고 설명합니다.
@inherited modification을 사용하는 주석 유형이 클래스에 사용되는 경우, 주석은 클래스의 서브 클래스에 사용됩니다.
2. 사용자 정의 주석
package com.joyfulmath.jvmexample.annnotaion; import java.lang.annotation.elementtype; import java.lang.antation.-enteration; import java.lang.annotation.retentionpolicy; import java.lang.annotation.targge;/*** @author deman.lu* @version of 2016-05-23. 13:36*/@target (ElementType.field) @retention (retentionpolicy.runtime) public @interface fruitname {String value () default ";} 우선, 주석에는 일반적으로 2 개의 메타 주석 수정이 필요합니다.
@Target (ElementType.field)
@retention (retentionpolicy.runtime)
특정 기능은 위에서 설명되었습니다.
모든 주석에는 "func"와 유사한 섹션이 있습니다. 이것은 주석 매개 변수로 이해 될 수 있습니다.
패키지 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 void void in); 이 코드의 로그 :
05-23 13 : 39 : 39 : 38.780 26792-26792/com.joyfulmath.jvmexample I/Apple : DisplayApPlename : null [at (apple.java:16)]
과제가 성공하지 못하는 이유는 무엇입니까? "Apple"에 파일을 할당하는 방법은 무엇입니까? 컴파일러가 아직 모르는 경우 수행하는 방법.
3. 주석 프로세서
또한 주석이 어떻게 작동하는지 설명하려면 프로세서가 필요합니다. 그렇지 않으면 주석과 거의 동일합니다.
반사를 통해 주석 내용을 얻을 수 있습니다.
package com.joyfulmath.jvmexample.annnotaion; import com.joyfulmath.jvmexample.traceLog; import java.lang.reflect.field;/*** @author deman.lu*@version 2016-05-23 14 : 08*/public stentinfoutils {class <clazz>?) ""; field [] fields = clazz.getDeclaredFields (); for (필드 필드 : 필드) {if (field.isAnnotationPresent (fruitname.class)) {fruitname fruitname = field.getAnnotation (fruitname.class); fruitnamest = fruitname.value (); tracelog.i (tracelog.i)}}.이것은 주석의 일반적인 사용입니다.
안드로이드 주석 프레임 워크 분석
위에서 볼 수 있듯이, 주석 프레임 워크의 사용에는 본질적으로 반사가 필요합니다.
그러나 반사 기능과 함께 주석 프레임 워크를 사용한다면 직접 사용할 수 있습니다. 더 간단합니다.
메커니즘이있는 경우, 특히 Android 개발 중에 많은 중복 코드를 쓰는 것을 피할 수 있습니다.
코드 패턴은 일관되지만 코드는 다릅니다. 현재 주석 프레임 워크를 사용하면 많은 개발 시간을 절약 할 수 있으며 물론 다른 오버 헤드가 증가 할 수 있습니다.
여기 Butterknife를 사용하는 예는 다음과 같습니다.
@bindstring (r.string.login_error)
문자열 loginerrormessage;
매우 간단한 것 같습니다. 문자열을 문자열 res에 해당하는 초기 값에 할당하는 것입니다. 이렇게하면 시간을 절약 할 수 있습니다. 물론 이것은 단지 예일뿐입니다.
다른 주석을 많이 사용하면 많은 개발 시간을 절약 할 수 있습니다.
그것이 어떻게 구현되는지 봅시다 :
패키지 버터 나이프; 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.retential policy.class; <fre> <code>* {@literal @} bindstring (r.string.username_error) 문자열 usernameerRortext;* </code> </pre>*/ @retention (field) public @interface bindstring {/** 문자열 자원 ID. */@stringres int value ();} BindString에는 값을 @StringRes에 할당하는 매개 변수, 즉 값이 하나뿐입니다.
위와 마찬가지로 위는 주석이 정의되고 사용되는 곳이지만 주석에 대한 실제 설명은 다음과 같습니다. Butterknifeprocessor
개인지도 <typeelement, bindingclass> findandparsetArgets (RoundEnvironment env)
이 함수는 일부 코드를 가로 채 웁니다.
// 각 @BindString 요소를 처리합니다 (요소 요소 : Env.GetElementAntOntOnTwith (bindString.class)) {if (! sperficialvalidation.validateElement (element)) 계속; try {parseresourcestring (exement, target classmap, eRASSESTARGETNAMES); {logpars, election, intorsingerors (element, ordeRersing, excep e); e);}} 바인드 스트링 주석의 모든 요소를 찾아 분석을 시작하십시오.
개인 void parseresourcestring (요소 요소, 맵 <typeelement, bindingclass> target classmap, set <typeelement> atrasedTargetNames) {boolean hasError = false; typeelement enclosingElement = (typeelement) 요소 .getenClingElement (); // target type이 string.if인지 확인합니다. (! string_type.equals (elemet 제한. HASERROR | = ISINACCESSIBLEVIAGENERATEDCODE (bindstring.class, "필드", 요소); hasError | = isbindingInwrongPackage (bindstring.class, element); if (haserror) {return;} // 필드에서 정보를 조립하십시오. element.getAnnotation (bindstring.class) .value (); bindingclass bindingclass = getorcreateTargetClass (TargetClassMap, EnclosingElement); FieldResourceBinding = New FieldResourceBinding (ID, 이름, "GetString", false); bindingclass.addresource (binding); rasedtargetnames.add (enclosingElement);} 먼저 요소가 문자열 유형인지 확인하십시오.
// 필드에서 정보를 조립합니다 .String name = element.getSimplename (). toString (); int id = element.getAntation (bindstring.class) .Value ();
필드 이름과 문자열 ID를 얻으십시오.
결정적인
Map <typeelement, bindingclass> targetclassmap
요소 및 주석 설명은지도에 하나씩 저장됩니다.
@override public boolean process (typeelement> elements, roundenvironment env) {map <typeelement, bindingclass> targetclassmap = findAndParsetAggets (ENV); for (map.Entry <typeelement, bindingClass> entry : targetClassMap.entryset ()) {typeelement = intrect. Entry.GetValue (); try {bindingclass.brewjava (). writeTo (filer);} catch (ioException e) {error (typeelement, "type view binder witt bind type for e.getmessage ());}}}}} 이것은 주석 프레임 워크가 시작된 곳, 독립적 인 프로세스입니다. 이 기사는 구체적인 세부 사항을 연구하지 않고,이를 명확히하십시오. 이것은 프레임 워크 중심의 장소입니다.
위의 정보에서 모든 주석 정보는 TargetClassMap에 저장됩니다.
위의 빨간색으로 표시된 코드는 주석 프레임 워크의 핵심이어야합니다.
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 (parentbinding.generatedClassName, targettype));} else {result.addsuperIntame.get (view_binder, targettype); adcet.dmethod (createBindMETHOD (targetTyPe)); if (isgeneratingUnbinder ()) {result.addtype (createUnbinderClass (targettype));} else if (! isfinal) {result.addMethod (createBindTotArgetMethod ());} return javafile.builder (generatedClassName.packagename (), build ( "). 버터 나이프에서. 수정하십시오! "). build ();} 이 구절의 핵심은 새 파일을 만드는 것입니다.
그런 다음 관련 내용을 작성하십시오.