از حاشیه نویسی برای مرتبط کردن ابرداده با عناصر برنامه در برنامه های جاوا خود استفاده کنید
شما احتمالاً با موقعیتهایی مواجه شدهاید که باید متادیتا (دادههایی که سایر دادهها را توصیف میکنند) با کلاسها، متدها و/یا سایر عناصر برنامه مرتبط کنید. به عنوان مثال، تیم برنامه نویسی شما ممکن است نیاز به شناسایی کلاس های ناتمام در یک برنامه بزرگ داشته باشد. برای هر کلاس ناتمام، ابرداده احتمالاً شامل نام توسعهدهنده مسئول تکمیل کلاس و تاریخ تکمیل مورد انتظار کلاس است.
قبل از جاوا ۵، نظرات تنها مکانیزم انعطافپذیری بودند که جاوا برای مرتبط کردن ابرداده با عناصر برنامه ارائه میکرد. با این حال، نظرات انتخاب ضعیفی هستند. از آنجا که کامپایلر آنها را نادیده می گیرد، نظرات در زمان اجرا در دسترس نیستند. و حتی اگر آنها در دسترس بودند، متن باید برای به دست آوردن موارد داده مهم تجزیه شود. بدون استاندارد کردن نحوه تعیین اقلام داده، تجزیه این اقلام داده ممکن است غیرممکن باشد.
مکانیسم های حاشیه نویسی غیر استاندارد
جاوا مکانیسمهای غیر استانداردی را برای مرتبط کردن ابرداده با عناصر برنامه فراهم میکند. به عنوان مثال، کلمه رزرو شده گذرا
به شما امکان میدهد فیلدهایی را که در طول سریالسازی حذف میشوند، حاشیهنویسی کنید (دادهها را با آنها مرتبط کنید).
جاوا ۵ با معرفی حاشیه نویسی، مکانیزم استانداردی برای مرتبط کردن ابرداده با عناصر مختلف برنامه، همه چیز را تغییر داد. این مکانیسم از چهار جزء تشکیل شده است:
- یک مکانیسم
@interface
برای اعلام انواع حاشیه نویسی. - انواع متا حاشیه نویسی، که می توانید از آنها برای شناسایی عناصر برنامه که یک نوع حاشیه نویسی برای آنها اعمال می شود استفاده کنید. برای شناسایی طول عمر یک حاشیه نویسی (نمونه ای از یک نوع حاشیه نویسی)؛ و بیشتر.
- پشتیبانی از پردازش حاشیه نویسی از طریق یک برنامه افزودنی به Java Reflection API (که در مقاله آینده مورد بحث قرار خواهد گرفت)، که می توانید از آن برای کشف حاشیه نویسی های زمان اجرا برنامه و یک ابزار کلی برای پردازش حاشیه نویسی استفاده کنید.
- انواع حاشیه نویسی استاندارد.
در حین انجام این مقاله نحوه استفاده از این مؤلفه ها را توضیح خواهم داد.
اعلام انواع حاشیه نویسی با @interface
می توانید با مشخص کردن نماد @
بلافاصله پس از آن کلمه رزرو شده interface
و یک شناسه، نوع حاشیه نویسی را اعلام کنید. به عنوان مثال، فهرست ۱ یک نوع حاشیه نویسی ساده را اعلام می کند که ممکن است از آن برای حاشیه نویسی کد ایمن رشته استفاده کنید.
فهرست ۱: ThreadSafe.java
public @interface ThreadSafe { }
بعد از اعلام این نوع حاشیهنویسی، پیشوند روشهایی را که در نظر میگیرید به عنوان thread-safe در نظر میگیرید، با نمونههایی از این نوع با اضافه کردن @
بلافاصله بهدنبال نام نوع به سربرگهای متد، قرار دهید. فهرست ۲ یک مثال ساده ارائه می دهد که در آن روش main()
حاشیه نویسی شده است @ThreadSafe
.
فهرست ۲: AnnDemo.java
(نسخه ۱)
public class AnnDemo { @ThreadSafe public static void main(String[] args) { } }
نمونه های
ThreadSafe
هیچ فراداده ای به جز نام نوع حاشیه نویسی ارائه نمی دهند. با این حال، میتوانید ابردادهها را با افزودن عناصر به این نوع ارائه کنید، جایی که یک عنصر سرصفحه روشی است که در بدنه نوع حاشیهنویسی قرار داده شده است.
علاوه بر نداشتن متن کد، عناصر مشمول محدودیتهای زیر نیز هستند:
- سرصفحه روش نمی تواند پارامترها را اعلام کند.
- سرصفحه روش نمیتواند یک بند پرتاب ارائه کند.
- نوع برگشتی هدر روش باید یک نوع اولیه باشد (به عنوان مثال،
int
)،java.lang.String
،java.lang.Class
، یک enum، یک نوع حاشیه نویسی، یا آرایه ای از یکی از این انواع. هیچ نوع دیگری را نمی توان برای نوع برگشتی تعیین کرد.
به عنوان مثالی دیگر، لیست ۳ یک نوع حاشیه نویسی ToDo
را با سه عنصر برای شناسایی یک کار کدگذاری خاص، مشخص کردن تاریخ اتمام کار و نامگذاری رمزگذار مسئول تکمیل کار ارائه می کند. .
فهرست ۳: ToDo.java
(نسخه ۱)
public @interface ToDo { int id(); String finishDate(); String coder() default "n/a"; }
توجه داشته باشید که هر عنصر هیچ پارامتر(ها) یا بند پرتابی را اعلام نمی کند، دارای یک نوع بازگشتی قانونی است (int
یا String
)، و با یک نقطه ویرگول خاتمه می یابد. همچنین، عنصر نهایی نشان می دهد که یک مقدار بازگشتی پیش فرض می تواند مشخص شود. زمانی که یک حاشیه نویسی مقداری را به عنصر اختصاص نمی دهد، این مقدار برگردانده می شود.
فهرست ۴ از ToDo
برای حاشیه نویسی روش کلاس ناتمام استفاده می کند.
فهرست ۴: AnnDemo.java
(نسخه ۲)
public class AnnDemo { public static void main(String[] args) { String[] cities = { "New York", "Melbourne", "Beijing", "Moscow", "Paris", "London" }; sort(cities); } @ToDo(id = 1000, finishDate = "10/10/2019", coder = "John Doe") static void sort(Object[] objects) { } }
فهرست ۴ یک مورد فراداده را به هر عنصر اختصاص می دهد. برای مثال، ۱۰۰۰
به id
اختصاص داده شده است. برخلاف coder
، عناصر id
و finishDate
باید مشخص شوند. در غیر این صورت، کامپایلر یک خطا را گزارش خواهد کرد. وقتی به coder
مقداری اختصاص داده نمیشود، مقدار پیشفرض "n/a"
را در نظر میگیرد.
جاوا یک عنصر String value()
ویژه ارائه میکند که میتواند برای برگرداندن فهرستی از موارد فراداده جدا شده با کاما استفاده شود. فهرست ۵ این عنصر را در نسخه بازسازی شده ToDo
نشان می دهد.
فهرست ۵: ToDo.java
(نسخه ۲)
public @interface ToDo { String value(); }
وقتی value()
تنها عنصر یک نوع حاشیه نویسی است، لازم نیست هنگام تخصیص value
و عملگر تخصیص =
را مشخص کنید. یک رشته به این عنصر فهرست ۶ هر دو رویکرد را نشان می دهد.
فهرست ۶: AnnDemo.java
(نسخه ۳)
public class AnnDemo { public static void main(String[] args) { String[] cities = { "New York", "Melbourne", "Beijing", "Moscow", "Paris", "London" }; sort(cities); } @ToDo(value = "1000,10/10/2019,John Doe") static void sort(Object[] objects) { } @ToDo("1000,10/10/2019,John Doe") static boolean search(Object[] objects, Object key) { return false; } }
استفاده از انواع متا حاشیه نویسی – مشکل انعطاف پذیری
می توانید انواع (مانند کلاس ها)، روش ها، متغیرهای محلی و موارد دیگر را حاشیه نویسی کنید. با این حال، این انعطاف پذیری می تواند مشکل ساز باشد. برای مثال، ممکن است بخواهید ToDo
را فقط به روشها محدود کنید، اما هیچ چیز مانع از استفاده آن برای حاشیهنویسی سایر عناصر برنامه نمیشود، همانطور که در فهرست ۷ نشان داده شده است.
فهرست ۷: AnnDemo.java
(نسخه ۴)
@ToDo("1000,10/10/2019,John Doe") public class AnnDemo { public static void main(String[] args) { @ToDo(value = "1000,10/10/2019,John Doe") String[] cities = { "New York", "Melbourne", "Beijing", "Moscow", "Paris", "London" }; sort(cities); } @ToDo(value = "1000,10/10/2019,John Doe") static void sort(Object[] objects) { } @ToDo("1000,10/10/2019,John Doe") static boolean search(Object[] objects, Object key) { return false; } }
در فهرست ۷، ToDo
همچنین برای حاشیه نویسی کلاس AnnDemo
و متغیر محلی cities
استفاده می شود. وجود این حاشیهنویسیهای اشتباه ممکن است کسی را که کد شما یا حتی ابزارهای پردازش حاشیهنویسی شما را بررسی میکند سردرگم کند. برای مواقعی که باید انعطافپذیری نوع حاشیهنویسی را محدود کنید، جاوا نوع حاشیهنویسی Target
را در بسته java.lang.annotation
خود ارائه میکند.
هدف
یک نوع متا حاشیه نویسی است – یک نوع حاشیه نویسی که حاشیه نویسی آن انواع حاشیه نویسی را نشان می دهد، برخلاف نوع غیر فرا حاشیه نویسی که حاشیه نویسی آن عناصر برنامه را حاشیه نویسی می کند. مانند کلاس ها و روش ها. انواع عناصر برنامهای را که نوع حاشیهنویسی برای آنها قابل اعمال است، شناسایی میکند. این عناصر با عنصر ElementValue[] value()
Target
شناسایی می شوند.
java.lang.annotation.ElementType
یک عدد است که ثابت های آن عناصر برنامه را توصیف می کنند. برای مثال، CONSTRUCTOR
برای سازنده ها و PARAMETER
برای پارامترها اعمال می شود. فهرست کردن ۸ refactors فهرست کردن نوع حاشیه نویسی ToDo
۵ تا فقط به روشها محدود شود.
فهرست ۸: ToDo.java
(نسخه ۳)
import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target({ElementType.METHOD}) public @interface ToDo { String value(); }
با توجه به نوع حاشیه نویسی اصلاح شده ToDo
، تلاش برای کامپایل لیست ۷ اکنون به پیام خطای زیر منجر می شود:
AnnDemo.java:1: error: annotation type not applicable to this kind of declaration @ToDo("1000,10/10/2019,John Doe") ^ AnnDemo.java:6: error: annotation type not applicable to this kind of declaration @ToDo(value="1000,10/10/2019,John Doe") ^ ۲ errors
انواع متا حاشیه نویسی اضافی
جاوا ۵ سه نوع متا حاشیه نویسی اضافی را معرفی کرد که در بسته java.lang.annotation
یافت می شوند:
نگهداری
نشان می دهد که حاشیه نویسی با نوع حاشیه نویسی چه مدت باید حفظ شود. enumjava.lang.annotation.RetentionPolicy
مرتبط این نوع، ثابتهایCLASS
را اعلام میکند (کامپایلر حاشیهنویسیها را در فایل کلاس ثبت میکند؛ ماشین مجازی آنها را برای ذخیره حافظه نگه نمیدارد – سیاست پیشفرض) ،RUNTIME
(کامپایلر حاشیه نویسی ها را در فایل کلاس ضبط می کند، ماشین مجازی آنها را حفظ می کند) وSOURCE
(کامپایلر حاشیه نویسی ها را کنار می گذارد).مستند شده
نشان میدهد که نمونههایی از حاشیهنویسیهایمستند شده
باید توسطjavadoc
و ابزارهای مشابه مستند شوند.ارثی
نشان می دهد که یک نوع حاشیه نویسی به طور خودکار به ارث می رسد.
جاوا ۸ نوع متا حاشیه نویسی java.lang.annotation.Repeatable
را معرفی کرد. Repeatable
برای نشان دادن اینکه نوع حاشیه نویسی که اعلان آن (meta-) حاشیه نویسی می کند، قابل تکرار است استفاده می شود. به عبارت دیگر، همانطور که در اینجا نشان داده شده است، می توانید چندین حاشیه نویسی را از یک نوع حاشیه نویسی تکرارپذیر به یک عنصر برنامه اعمال کنید:
@ToDo(value = "1000,10/10/2019,John Doe") @ToDo(value = "1001,10/10/2019,Kate Doe") static void sort(Object[] objects) { }
این مثال فرض می کند که ToDo
با نوع حاشیه نویسی Repeatable
حاشیه نویسی شده است.
در حال پردازش حاشیه نویسی
حاشیه نویسی باید پردازش شود. در غیر این صورت، داشتن آنها فایده ای ندارد. جاوا ۵ API Reflection را گسترش داد تا به شما کمک کند ابزارهای پردازش حاشیه نویسی خود را ایجاد کنید. برای مثال، Class
یک Annotation[]
که آرایهای از نمونههای
متد getAnnotations()java.lang.Annotation
را برمیگرداند که حاشیهنویسیهای موجود در عنصر توصیفشده توسط شی Class
را توصیف میکند.
فهرست ۹ یک برنامه کاربردی ساده را ارائه میکند که یک فایل کلاس را بارگیری میکند، روشهای آن را برای حاشیهنویسیهای ToDo
بازجویی میکند، و اجزای هر حاشیهنویسی یافت شده را خروجی میدهد.
فهرست ۹: AnnProcDemo.java
import java.lang.reflect.Method; public class AnnProcDemo { public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("usage: java AnnProcDemo classfile"); return; } Method[] methods = Class.forName(args[0]).getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].isAnnotationPresent(ToDo.class)) { ToDo todo = methods[i].getAnnotation(ToDo.class); String[] components = todo.value().split(","); System.out.printf("ID = %s%n", components[0]); System.out.printf("Finish date = %s%n", components[1]); System.out.printf("Coder = %s%n%n", components[2]); } } } }
پس از تأیید اینکه دقیقاً یک آرگومان خط فرمان (شناسایی یک فایل کلاس) مشخص شده است، main()
فایل کلاس را از طریق Class.forName()
بارگیری می کند، getMethods()
را فراخوانی می کند تا آرایه ای از اشیاء java.lang.reflect.Method
را که همه متدهای public
را در فایل کلاس شناسایی می کند، برگرداند و اینها را پردازش می کند. روش ها.
پردازش روش با فراخوانی روش
boolean isAnnotationPresent(Class extensions) آغاز می شود
روش Annotation> annotationClass)
برای تعیین اینکه آیا حاشیه نویسی توصیف شده توسط ToDo.class
در روش وجود دارد یا خیر. اگر چنین است، روش
برای به دست آوردن حاشیه نویسی فراخوانی می شود.
روش annotationClass)
یادداشتهای ToDo
که پردازش میشوند، آنهایی هستند که انواع آنها یک عنصر String value()
را اعلام میکنند (به فهرست ۵ مراجعه کنید). از آنجا که ابرداده مبتنی بر رشته این عنصر با کاما از هم جدا شده است، باید به آرایه ای از مقادیر مؤلفه تقسیم شود. سپس به هر یک از سه مقدار مؤلفه دسترسی یافته و خروجی داده می شود.
این کد منبع (javac AnnProcDemo.java
) را کامپایل کنید. قبل از اینکه بتوانید برنامه را اجرا کنید، به یک فایل کلاس مناسب با حاشیه نویسی @ToDo
در روش های public
آن نیاز دارید. برای مثال، میتوانید کد منبع فهرست ۶ AnnDemo
را تغییر دهید تا public
را در sort()
و search()
سرصفحه های روش. همچنین به نوع حاشیه نویسی ToDo
Listing 10 نیاز دارید که به خط مشی حفظ RUNTIME
نیاز دارد.
فهرست ۱۰: ToDo.java
(نسخه ۴)
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface ToDo { String value(); }
AnnDemo.java
و لیست ۱۰ تغییر یافته را کامپایل کنید و دستور زیر را برای پردازش حاشیه نویسی های AnnDemo
ToDo
اجرا کنید:
java AnnProcDemo AnnDemo
اگر همه چیز خوب پیش رفت، باید خروجی زیر را مشاهده کنید:
ID = 1000 Finish date = 10/10/2019 Coder = John Doe ID = 1000 Finish date = 10/10/2019 Coder = John Doe
پردازش حاشیه نویسی با apt و کامپایلر جاوا
جاوا ۵ ابزار apt
را برای پردازش حاشیه نویسی ها به صورت کلی معرفی کرد. جاوا ۶ عملکرد apt
را به ابزار کامپایلر javac
خود منتقل کرد و جاوا ۷ apt
را منسوخ کرد که متعاقبا حذف شد (با جاوا ۸ شروع شد) .
انواع حاشیه نویسی استاندارد
جاوا ۵ همراه با هدف
، Retention
، مستند شده
و ارثی
، java را معرفی کرد. lang.Deprecated
، java.lang.Override
و java.lang.SuppressWarnings
. این سه نوع حاشیه نویسی فقط برای استفاده در زمینه کامپایلر طراحی شده اند، به همین دلیل خط مشی های حفظ آنها روی SOURCE
تنظیم شده است.
پست های مرتبط
نحوه توصیف کد جاوا با حاشیه نویسی
نحوه توصیف کد جاوا با حاشیه نویسی
نحوه توصیف کد جاوا با حاشیه نویسی