1. 몇 가지 기본 개념
시작하기 전에 우리는 중요한 것을 선언해야합니다. 우리는 런타임시 반사 메커니즘을 통해 처리되는 주석을 논의하지 않고 컴파일 시간에 처리되는 주석에 대해 논의합니다.
컴파일 타임 주석과 런타임 주석의 차이점은 무엇입니까? 실제로, 그것은 주로 성능 문제로 인해 크지 않습니다. 런타임 주석은 주로 반사에 전적으로 의존하며 반사 효율은 기본 제품의 효율성보다 느리므로 메모리가 적고 CPU가 열악한 기계에 약간의 지연이 있습니다. 그러나 컴파일 프로세스 (Java-> 클래스)에서 일부 주석 마크는 일부 클래스 나 파일을 동적으로 생성하는 데 사용되므로 APK 작업과 관련이 없으므로 성능 문제가 없기 때문에이 문제는 전혀 문제가되지 않습니다. 따라서보다 유명한 오픈 소스 프로젝트가 주석 함수를 사용하는 경우 일반적으로 컴파일 타임 주석을 사용합니다.
주석 프로세서는 편집 기간 동안 주석 정보를 스캔하고 처리하는 데 사용되는 Javac과 함께 제공되는 도구입니다. 특정 주석에 대해 자신의 주석 프로세서를 등록 할 수 있습니다. 여기서 나는 당신이 이미 주석이 무엇인지, 그리고 그것들을 사용자 정의하는 방법을 이미 이해한다고 가정합니다. 아직 주석을 이해하지 못한 경우 공식 문서를 확인할 수 있습니다. 주석 프로세서는 이미 Java 5에 존재했지만 Java 6 (2006 년 12 월에 출시 될 때까지 API는 없었습니다. Java 사용자가 주석 프로세서의 힘을 깨닫기까지는 시간이 걸렸습니다. 그래서 최근 몇 년 동안 인기를 얻었습니다.
특정 주석이있는 프로세서는 Java 소스 코드 (또는 Bytecode)를 입력으로 가져간 다음 일부 파일 (일반적으로 .java 파일)을 출력으로 생성합니다. 그게 무슨 뜻입니까? Java 코드를 생성 할 수 있습니다! 이 Java 코드는 생성 된 .java 파일에 있습니다. 따라서 메소드 추가와 같은 기존 Java 클래스를 변경할 수 없습니다. 이 생성 된 Java 파일은 다른 수동으로 작성된 Java 소스 코드와 마찬가지로 Javac에 의해 컴파일됩니다.
주석 처리는 컴파일 단계에서 실행됩니다. 그 원칙은 Java 소스 코드를 읽고 주석을 구문 분석 한 다음 새 Java 코드를 생성하는 것입니다. 새로 생성 된 Java 코드는 마침내 Java Bytecode로 컴파일됩니다. 주석 프로세서는 Java 메소드 추가 또는 삭제와 같은 읽기 Java 클래스를 변경할 수 없습니다.
2. AbstractProcessor
프로세서의 API를 살펴 보겠습니다. 모든 프로세서는 다음과 같이 AbstractProcessor를 상속합니다.
패키지 com.example; import java.util.linkedhashset; import java.util.set; import javax.annotation.processing.abstractprocessor; import javax.annotation.processing.processingenvironment; import javax.annotation.roundenvironment; import; javax.annotation.processing.supportedannotationtypes; import javax.annotation.processing.supportedsourceversion; import javax.lang.model.sourceversion; import javax.lang.model.element.typeelement; public myprocessor (problother extends problics) typeelement> 공지 사항, Roundenvironment Env) {return false; } @override public set <string> getSupportedAnnotationTypes () {set <string> annotataions = new LinkedHashset <string> (); Annotataions.add ( "com.example.myAnnotation"); 리턴 주석; } @override public sourceversion getSupportedSourceVersion () {return sourceVersion.latestSupported (); } @override public synchronized void init (ProcessingEnvironment ProcessingEnv) {super.init (ProcessingEnv); }}init (ProcessingEnvironment ProcessingEnv) : 모든 주석 프로세서 클래스에는 매개 변수가없는 생성자가 있어야합니다. 그러나 주석 처리 도구에 의해 호출되는 특수 메소드 init ()가 있습니다. ProcessingEnvironment는 실용적인 도구 클래스 요소, 유형 및 파일러를 제공합니다. 나중에 사용할 것입니다.
process(Set<? extends TypeElement> annoations, RoundEnvironment env) : 이는 각 프로세서의 main () 메소드와 유사합니다. 이 방법에서 스캔 및 구현, 주석 처리 및 Java 파일을 생성 할 수 있습니다. RoundEnvironment 매개 변수를 사용하면 특정 주석으로 주석이 달린 요소를 쿼리 할 수 있습니다 (원본 텍스트 : 특정 주석으로 주석이 달린 요소에 대한 쿼리가 가능함). 나중에 세부 사항을 볼 수 있습니다.
getSupportedAnnotationTypes(): 이 메소드에서는 주석 프로세서에서 등록 해야하는 주석을 지정해야합니다. 리턴 값은 주석 프로세서가 처리하려는 주석 유형의 전체 이름을 포함하는 문자열 컬렉션입니다. 다시 말해, 주석 프로세서가 처리 할 주석이 여기에 정의됩니다.
getSupportedSourceVersion() : 사용하는 Java 버전을 지정하는 데 사용됩니다. 일반적으로 SourceVersion.latestSupported() 반환해야합니다. 그러나 Java 6을 고수 할 충분한 이유가 있으면 SourceVersion.RELEASE_6 반환 할 수도 있습니다. SourceVersion.latestSupported() 사용하는 것이 좋습니다. Java 7에서는 주석을 사용하여 getSupportedAnnotationTypes() 및 getSupportedSourceVersion() 대체 할 수도 있습니다.
@SupportedSourceVersion (value = sourceversion.release_7) @SupportedAnnotationTypes ({// 전체 QULIFEND 주석 유형 이름 "com.example.MyAnnotation", "com.example.anotherAnnotation"}) public myprocessor extend <@overrider volement (etlends), exteelend> extelends extelends problications (exteelend) problicestements intovelends public extreeancessor extreeanprocessor. Roundenvironment Env) {return false; } @override public synchronized void init (ProcessingEnvironment ProcessingEnv) {super.init (processingenv); }} 호환성 문제, 특히 Android의 경우 @SupportedAnnotationTypes 및 @SupportedSourceVersion 사용하는 대신 getSupportedAnnotationTypes() 및 getSupportedSourceVersion() 다시 작성하는 것이 좋습니다.
다음으로 알아야 할 것은 주석 프로세서가 자체 JVM으로 실행됩니다. 예, 당신은 그 것을 읽습니다. Javac은 주석 프로세서를 실행하기 위해 완전한 Java Virtual Machine을 시작합니다. 그게 무슨 뜻입니까? 일반적인 Java 프로그램에서 사용하는 모든 것을 사용할 수 있습니다. 구아바 사용! Dagger 또는 사용하려는 다른 클래스 라이브러리와 같은 종속성 주입 도구를 사용할 수 있습니다. 그러나 작은 프로세서 일지라도 다른 Java 프로그램을 개발하는 것과 마찬가지로 효율적인 알고리즘과 설계 패턴을 사용하는 데주의를 기울여야한다는 것을 잊지 마십시오.
3. 프로세서를 등록하십시오
"주석 프로세서를 Javac에 등록하는 방법"을 물을 수 있습니다. .jar 파일을 제공해야합니다. 다른 .jar 파일과 마찬가지로 이미 컴파일 된 주석 프로세서를이 파일에 패키지합니다. 또한 .jar 파일에서 특수 파일 javax.annotation.processing.processor를 Meta-Inf/Services 디렉토리에 포장해야합니다. 따라서 .jar 파일 디렉토리 구조는 다음과 같습니다.
myProcess.jar -com -example -myprocess.class -meta -inf -services -javax.annotation.processing.processor
javax.annotation.processing.processor 파일의 내용은 목록이며 각 줄은 주석 프로세서의 전체 이름입니다. 예를 들어:
com.example.myProcess
com.example.anotherprocess
4. 예 : 공장 모델
우리가 해결하고 싶은 문제는 다음과 같습니다. 우리는 피자 가게를 구현하고 싶습니다. 피자 스토어는 고객에게 디저트 티라미수 (Tiramisu)뿐만 아니라 2 개의 피자 (마르 게리타 및 칼 존)를 제공합니다.
공개 인터페이스 식사 {public float getPrice ();} 공개 클래스 Margheritapizza는 식사 {@override public float getPrice () {return 6.0f; }} 공개 클래스 CalzonePizza는 식사를 구현합니다. }} 공개 클래스 Tiramisu는 식사를 구현합니다. {@override public float getPrice () {return 4.5f; }} public class pizzastore {public meal Order (string ealingname) {if (null == fialname) {throw new 불법 행위 값 ( "식사 이름은 null!"); } if ( "margherita".equals (dealname)) {return new margheritapizza (); } if ( "calzone".equals (dealname)) {return new calzonepizza (); } if ( "Tiramisu".Equals (dealName)) {return new Tiramisu (); } 새로운 불법 행위 exception을 던지십시오 ( "알 수없는 식사" " + 니스 이름 +" ""); } private static string readConsole () {스캐너 스캐너 = 새 스캐너 (System.In); 문자열 식사 = 스캐너 .nextline (); 스캐너 .Close (); 반환 식사; } public static void main (String [] args) {System.out.println ( "피자 스토어에 오신 것을 환영합니다"); Pizzastore Pizzastore = New Pizzastore (); 식사 식사 = pizzastore.order (readConsole ()); System.out.println ( "Bill : $" + 니스 .getPrice ()); }}보시다시피, 순서 () 메소드에서는 많은 if 조건 판단 진술이 있습니다. 그리고 새로운 피자를 추가하면 새로운 IF 조건부 판단을 추가해야합니다. 그러나 주석 프로세서와 공장 모드를 사용하여 주석 프로세서가 IF 문을 생성 할 수 있습니다. 이런 식으로 우리가 원하는 코드는 다음과 같습니다.
공개 클래스 피자 가스토르 {private yealfactory factory = new MealFactory (); 공개 식사 명령 (String MealName) {return factory.create (dealname); } private static string readConsole () {스캐너 스캐너 = 새 스캐너 (System.In); 문자열 식사 = 스캐너 .nextline (); 스캐너 .Close (); 반환 식사; } public static void main (String [] args) {System.out.println ( "피자 스토어에 오신 것을 환영합니다"); Pizzastore Pizzastore = New Pizzastore (); 식사 식사 = pizzastore.order (readConsole ()); System.out.println ( "Bill : $" + 니스 .getPrice ()); }} public class fealFactory {public meal create (string id) {if (id == null) {새로운 불법 불법 행위 ( "id is null!"); } if ( "calzone".equals (id)) {return new calzonepizza (); } if ( "Tiramisu".Equals (id)) {return new Tiramisu (); } if ( "margherita".equals (id)) {return new margheritapizza (); } 새로운 불법 행위 exception 던지기 ( "알 수없는 id =" + id); }}5. @factory 주석
주석 프로세서를 사용하여 식사 기능 수업을 생성 할 계획이라고 생각할 수 있습니까? 보다 일반적으로, 우리는 공장 수업을 생성하기위한 주석과 프로세서를 제공하고자합니다.
@factory 주석을 살펴 보겠습니다.
@TARGET (ElementType.type) @retention (retentionpolicy.class) public @interface factory { / ** * 공장의 이름 * / class <?> type (); / ** * 인스턴스화 해야하는 항목을 결정하기위한 식별자 */ String ID ();}아이디어는 다음과 같습니다. 우리는 이러한 음식 수업에 주석을 달고, 유형 ()을 사용 하여이 클래스가 속한 공장을 표시하고 ID ()를 사용 하여이 클래스의 특정 유형을 나타냅니다. @factory 주석을이 클래스에 적용합시다.
@factory (type = margheritapizza.class, id = "margherita") 공개 클래스 Margheritapizza는 식사 {@override public float getPrice () {return 6.0f; }} @factory (type = calzonepizza.class, id = "calzone") 공개 클래스 CalzonePizza는 식사 {@override public float getPrice () {return 8.5f; }} @factory (type = tiramisu.class, id = "tiramisu") 공개 클래스 Tiramisu는 식사 {@override public float getPrice () {return 4.5f; }}@factory 주석을 식사 인터페이스에 적용 할 수 있습니까? 주석을 물려받을 수 없기 때문에 대답은 아니오입니다. 즉, 클래스 X에 주석이있는 경우 클래스 Y는 X를 연장하고 클래스 Y는 클래스 X의 주석을 상속하지 않습니다. 프로세서를 작성하기 전에 몇 가지 규칙을 명확히해야합니다.
주석 프로세서 :
공개 클래스 FactoryProcessor는 AbstractProcessor를 확장합니다. 개인 요소 요소; 개인 파일러 제출자; 개인 Messager Messager; Private Map <String, FactoryGroupedClasses> FactoryClasses = New LinkedHashmap <String, FactoryGroupedClasses> (); @override public synchronized void init (ProcessingEnvironment ProcessingEnv) {super.init (ProcessingEnv); TypeUtils = ProcessingEnv.getTypeutils (); Elementutils = ProcessingEnv.getElementUtils (); filer = processingenv.getfiler (); Messager = ProcessingEnv.getMessager (); } @override public boolean process (set <? extends typeelement> arg0, roundenvironment arg1) {... return false; } @override public set <string> getSupportedAnnotationTypes () {set <string> annotataions = new LinkedHashset <string> (); Annotataions.add (factory.class.getCanonicalName ()); 리턴 주석; } @override public sourceversion getSupportedSourceVersion () {return sourceVersion.latestSupported (); }} getSupportedAnnotationTypes() 메소드에서 @factory 주석 이이 프로세서에 의해 처리되도록 지정합니다.
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.