۳۰ آذر ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

نحوه توصیف کد جاوا با حاشیه نویسی

از حاشیه نویسی برای مرتبط کردن ابرداده با عناصر برنامه در برنامه های جاوا خود استفاده کنید

از حاشیه نویسی برای مرتبط کردن ابرداده با عناصر برنامه در برنامه های جاوا خود استفاده کنید

شما احتمالاً با موقعیت‌هایی مواجه شده‌اید که باید متادیتا (داده‌هایی که سایر داده‌ها را توصیف می‌کنند) با کلاس‌ها، متدها و/یا سایر عناصر برنامه مرتبط کنید. به عنوان مثال، تیم برنامه نویسی شما ممکن است نیاز به شناسایی کلاس های ناتمام در یک برنامه بزرگ داشته باشد. برای هر کلاس ناتمام، ابرداده احتمالاً شامل نام توسعه‌دهنده مسئول تکمیل کلاس و تاریخ تکمیل مورد انتظار کلاس است.

قبل از جاوا ۵، نظرات تنها مکانیزم انعطاف‌پذیری بودند که جاوا برای مرتبط کردن ابرداده با عناصر برنامه ارائه می‌کرد. با این حال، نظرات انتخاب ضعیفی هستند. از آنجا که کامپایلر آنها را نادیده می گیرد، نظرات در زمان اجرا در دسترس نیستند. و حتی اگر آنها در دسترس بودند، متن باید برای به دست آوردن موارد داده مهم تجزیه شود. بدون استاندارد کردن نحوه تعیین اقلام داده، تجزیه این اقلام داده ممکن است غیرممکن باشد.

مکانیسم های حاشیه نویسی غیر استاندارد

جاوا مکانیسم‌های غیر استانداردی را برای مرتبط کردن ابرداده با عناصر برنامه فراهم می‌کند. به عنوان مثال، کلمه رزرو شده گذرا به شما امکان می‌دهد فیلدهایی را که در طول سریال‌سازی حذف می‌شوند، حاشیه‌نویسی کنید (داده‌ها را با آنها مرتبط کنید).

جاوا ۵ با معرفی حاشیه نویسی، مکانیزم استانداردی برای مرتبط کردن ابرداده با عناصر مختلف برنامه، همه چیز را تغییر داد. این مکانیسم از چهار جزء تشکیل شده است:

  • یک مکانیسم @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 هیچ فراداده ای به جز نام نوع حاشیه نویسی ارائه نمی دهند. با این حال، می‌توانید ابرداده‌ها را با افزودن عناصر به این نوع ارائه کنید، جایی که یک عنصر سرصفحه روشی است که در بدنه نوع حاشیه‌نویسی قرار داده شده است.

Rust در شاخص محبوبیت زبان به جلو می رود

علاوه بر نداشتن متن کد، عناصر مشمول محدودیت‌های زیر نیز هستند:

  • سرصفحه روش نمی تواند پارامترها را اعلام کند.
  • سرصفحه روش نمی‌تواند یک بند پرتاب ارائه کند.
  • نوع برگشتی هدر روش باید یک نوع اولیه باشد (به عنوان مثال، intjava.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 یافت می شوند:

  • نگهداری نشان می دهد که حاشیه نویسی با نوع حاشیه نویسی چه مدت باید حفظ شود. enum java.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 annotationClass) برای تعیین اینکه آیا حاشیه نویسی توصیف شده توسط ToDo.class در روش وجود دارد یا خیر. اگر چنین است، روش T getAnnotation(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 تنظیم شده است.

منسوخ شده