۲۹ شهریور ۱۴۰۳

Techboy

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

مقداردهی اولیه کلاس و شی در جاوا

در اینجا همه چیزهایی است که باید در مورد مقداردهی اولیه کلاس ها و اشیاء جاوا قبل از اجرای آنها در JVM بدانید.

در اینجا همه چیزهایی است که باید در مورد مقداردهی اولیه کلاس ها و اشیاء جاوا قبل از اجرای آنها در JVM بدانید.

کلاس ها و اشیاء در جاوا باید قبل از استفاده مقداردهی اولیه شوند. شما قبلاً یاد گرفته‌اید که فیلدهای کلاس در هنگام بارگیری کلاس‌ها به مقادیر پیش‌فرض مقداردهی اولیه می‌شوند، و اشیاء از طریق سازنده‌ها مقداردهی اولیه می‌شوند—اما هنوز چیزهای بیشتری برای مقداردهی اولیه وجود دارد. این آموزش تمام ویژگی های جاوا را برای مقداردهی اولیه کلاس ها و اشیاء معرفی می کند.

آنچه در این آموزش جاوا خواهید آموخت

  • نحوه تنظیم اولیه کلاس جاوا
  • نحوه کار با بلوک های اولیه سازی کلاس
  • نحوه مقداردهی اولیه اشیاء جاوا

چگونه یک کلاس جاوا را مقداردهی اولیه کنیم

قبل از اینکه پشتیبانی جاوا برای مقداردهی اولیه کلاس را بررسی کنیم، اجازه دهید مراحل اولیه سازی یک کلاس جاوا را دوباره مرور کنیم. فهرست ۱ را در نظر بگیرید.

class SomeClass
{
   static boolean b;
   static byte by;
   static char c;
   static double d;
   static float f;
   static int i;
   static long l;
   static short s;
   static String st;
}

فهرست ۱ کلاس SomeClass را اعلام می‌کند. این کلاس نه فیلد از انواع boolean، byte، char، double، float، int، long، کوتاه و رشته. هنگامی که SomeClass بارگیری می‌شود، بیت‌های هر فیلد روی صفر تنظیم می‌شوند که به صورت زیر تفسیر می‌کنید:

false
۰
\u0000
۰.۰
۰.۰
۰
۰
۰
null

فیلدهای کلاس قبلی به طور ضمنی به صفر مقداردهی شدند. با این حال، همانطور که در فهرست ۲ نشان داده شده است، می توانید به طور صریح فیلدهای کلاس را با اختصاص مستقیم مقادیر به آنها مقداردهی اولیه کنید.

class SomeClass
{
   static boolean b = true;
   static byte by = 1;
   static char c = 'A';
   static double d = 2.0;
   static float f = 3.0f;
   static int i = 4;
   static long l = 5000000000L;
   static short s = 20000;
   static String st = "abc";
}

مقدار هر تکلیف باید با نوع فیلد کلاس سازگار باشد. هر متغیر مقدار را مستقیماً ذخیره می کند، به استثنای st. متغیر st ارجاع به یک شی String را ذخیره می کند که حاوی abc است.

ارجاع به فیلدهای کلاس

هنگام مقداردهی اولیه یک فیلد کلاس، قانونی است که آن را به مقدار فیلد کلاسی که قبلاً مقداردهی اولیه شده است، مقداردهی کنید. به عنوان مثال، فهرست ۳ مقدار y را به مقدار x مقداردهی می‌کند. هر دو فیلد به ۲ مقداردهی اولیه می شوند.

class SomeClass
{
   static int x = 2;
   static int y = x;

   public static void main(String[] args)
   {
      System.out.println(x);
      System.out.println(y);
   }
}

با این حال، معکوس آن قانونی نیست: شما نمی توانید یک فیلد کلاس را به مقدار یک فیلد کلاس اعلام شده بعدی مقداردهی کنید. کامپایلر جاوا وقتی با این سناریو مواجه می شود، مرجع ارسال غیر قانونی را خروجی می دهد. فهرست ۴ را در نظر بگیرید.

class SomeClass
{
   static int x = y;
   static int y = 2;

   public static void main(String[] args)
   {
      System.out.println(x);
      System.out.println(y);
   }
}

کامپایلر وقتی با static int x = y; مواجه شد، مرجع ارسال غیرقانونی را گزارش می‌کند. این به این دلیل است که کد منبع از بالا به پایین کامپایل شده است و کامپایلر هنوز y را ندیده است. (اگر y به طور صریح مقداردهی نشده باشد، این پیام را نیز خروجی می دهد.)

نحوه کار با بلوک های اولیه سازی کلاس

در برخی موارد، ممکن است بخواهید اولیه سازی های پیچیده مبتنی بر کلاس را انجام دهید. شما این کار را بعد از بارگیری یک کلاس و قبل از ایجاد هر شیء از آن کلاس انجام خواهید داد (با فرض اینکه کلاس یک کلاس کاربردی نباشد). برای این کار می توانید از بلوک اولیه سازی کلاس استفاده کنید.

یک بلوک اولیه سازی کلاس بلوکی از عبارات است که قبل از آن کلمه کلیدی static وارد بدنه کلاس می شود. هنگامی که کلاس بارگذاری می شود، این دستورات اجرا می شوند. فهرست ۵ را در نظر بگیرید.

class Graphics
{
   static double[] sines, cosines;
   static
   {
      sines = new double[360];
      cosines = new double[360];
      for (int i = 0; i < sines.length; i++)
      {
         sines[i] = Math.sin(Math.toRadians(i));
         cosines[i] = Math.cos(Math.toRadians(i));
      }
   }
}

فهرست ۵ یک کلاس Graphics را اعلام می کند که متغیرهای آرایه سینوس و cosines را اعلام می کند. همچنین یک بلوک اولیه سازی کلاس را اعلام می کند که آرایه های ۳۶۰ عنصری را ایجاد می کند که مراجع آنها به سینوس و cosines اختصاص داده می شوند. سپس با فراخوانی sin() و sin() کلاس Math از یک عبارت for برای مقداردهی اولیه این عناصر آرایه به مقادیر سینوسی و کسینوس مناسب استفاده می کند. متدهای code>cos(). (ریاضی بخشی از کتابخانه کلاس استاندارد جاوا است. در مقاله آینده درباره این کلاس و این روش ها صحبت خواهم کرد.)

ترفند عملکرد

از آنجایی که عملکرد برای برنامه های گرافیکی مهم است و از آنجا که دسترسی به عنصر آرایه سریعتر از فراخوانی یک روش است، توسعه دهندگان به ترفندهای عملکردی مانند ایجاد و مقداردهی اولیه آرایه های سینوس و کسینوس متوسل می شوند.

ترکیب اولیه سازهای فیلد کلاس و بلوک های اولیه سازی کلاس

شما می توانید چندین مقداردهی اولیه فیلد کلاس و بلوک های اولیه سازی کلاس را در یک برنامه کاربردی ترکیب کنید. فهرست ۶ مثالی را ارائه می دهد.

class MCFICIB
{
   static int x = 10;

   static double temp = 98.6;

   static
   {
      System.out.println("x = " + x);
      temp = (temp - 32) * 5.0/9.0; // convert to Celsius
      System.out.println("temp = " + temp);
   }

   static int y = x + 5;

   static
   {
      System.out.println("y = " + y);
   }

   public static void main(String[] args)
   {
   }
}

لیست ۶ یک جفت فیلد کلاس (x و y) را اعلام و مقداردهی اولیه می‌کند، و یک جفت مقداردهی اولیه static را اعلام می‌کند. این فهرست را مطابق شکل کامپایل کنید:

javac MCFICIB.java

سپس برنامه به دست آمده را اجرا کنید:

java MCFICIB

شما باید خروجی زیر را مشاهده کنید:

x = 10
temp = 37.0
y = 15

این خروجی نشان می‌دهد که مقداردهی اولیه کلاس به ترتیب از بالا به پایین انجام می‌شود.

روش‌های

()

هنگام کامپایل کردن اولیه سازهای کلاس و بلوک های اولیه سازی کلاس، کامپایلر جاوا بایت کد کامپایل شده را (به ترتیب از بالا به پایین) در روش خاصی به نام () ذخیره می کند. براکت های زاویه ای از تضاد نام جلوگیری می کنند: نمی توانید یک روش () را در کد منبع اعلام کنید زیرا < و > کاراکترهای در زمینه شناسه غیرقانونی هستند.

بعد از بارگیری کلاس، JVM قبل از فراخوانی main() (زمانی که main() وجود دارد، این متد را فراخوانی می‌کند.

بیایید نگاهی به داخل MCFICIB.class بیندازیم. جداسازی جزئی زیر اطلاعات ذخیره شده را برای فیلدهای x، temp و y نشان می‌دهد:

Field #1

۰۰۰۰۰۲۹۰        Access Flags                          ACC_STATIC
۰۰۰۰۰۲۹۲        Name                                  x
۰۰۰۰۰۲۹۴        Descriptor                            I
۰۰۰۰۰۲۹۶        Attributes Count                      0

Field #2

۰۰۰۰۰۲۹۸        Access Flags                          ACC_STATIC
۰۰۰۰۰۲۹a        Name                                  temp
۰۰۰۰۰۲۹c        Descriptor                            D
۰۰۰۰۰۲۹e        Attributes Count                      0

Field #3

۰۰۰۰۰۲a0        Access Flags                          ACC_STATIC
۰۰۰۰۰۲a2        Name                                  y
۰۰۰۰۰۲a4        Descriptor                            I
۰۰۰۰۰۲a6        Attributes Count                      0

خط Descriptor نوع توصیفگر JVM را برای فیلد مشخص می‌کند. نوع با یک حرف نشان داده می شود: I برای int و D برای double.

جداسازی جزئی زیر، توالی دستورالعمل بایت کد را برای روش () نشان می دهد. هر خط با یک عدد اعشاری شروع می شود که آدرس آفست مبتنی بر صفر دستورالعمل بعدی را مشخص می کند:

  ۰        bipush 10
  ۲        putstatic MCFICIB/x I
  ۵        ldc2_w #98.6
  ۸        putstatic MCFICIB/temp D
 ۱۱        getstatic java/lang/System/out Ljava/io/PrintStream;
 ۱۴        new java/lang/StringBuilder
 ۱۷        dup
 ۱۸        invokespecial java/lang/StringBuilder/<init>()V
 ۲۱        ldc "x = "
 ۲۳        invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
 ۲۶        getstatic MCFICIB/x I
 ۲۹        invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;
 ۳۲        invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String;
 ۳۵        invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
 ۳۸        getstatic MCFICIB/temp D
 ۴۱        ldc2_w #32
 ۴۴        dsub
 ۴۵        ldc2_w #5
 ۴۸        dmul
 ۴۹        ldc2_w #9
 ۵۲        ddiv
 ۵۳        putstatic MCFICIB/temp D
 ۵۶        getstatic java/lang/System/out Ljava/io/PrintStream;
 ۵۹        new java/lang/StringBuilder
 ۶۲        dup
 ۶۳        invokespecial java/lang/StringBuilder/<init>()V
 ۶۶        ldc "temp = "
 ۶۸        invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
 ۷۱        getstatic MCFICIB/temp D
 ۷۴        invokevirtual java/lang/StringBuilder/append(D)Ljava/lang/StringBuilder;
 ۷۷        invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String;
 ۸۰        invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
 ۸۳        getstatic MCFICIB/x I
 ۸۶        iconst_5
 ۸۷        iadd
 ۸۸        putstatic MCFICIB/y I
 ۹۱        getstatic java/lang/System/out Ljava/io/PrintStream;
 ۹۴        new java/lang/StringBuilder
 ۹۷        dup
 ۹۸        invokespecial java/lang/StringBuilder/<init>()V
۱۰۱        ldc "y = "
۱۰۳        invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
۱۰۶        getstatic MCFICIB/y I
۱۰۹        invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;
۱۱۲        invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String;
۱۱۵        invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
۱۱۸        return

توالی دستورالعمل از offset 0 تا offset 2 معادل اولیه ساز فیلد کلاس زیر است:

static int x = 10;

توالی دستورالعمل از offset 5 تا offset 8 معادل اولیه ساز فیلد کلاس زیر است:

static double temp = 98.6;

توالی دستورالعمل از افست ۱۱ تا آفست ۸۰ معادل بلوک اولیه سازی کلاس زیر است:

static
{
   System.out.println("x = " + x);
   temp = (temp - 32) * 5.0/9.0; // convert to Celsius
   System.out.println("temp = " + temp);
}

توالی دستورالعمل از offset 83 تا offset 88 معادل اولیه ساز فیلد کلاس زیر است:

static int y = x + 5;

توالی دستورالعمل از offset 91 تا offset 115 معادل بلوک اولیه سازی کلاس زیر است:

static
{
   System.out.println("y = " + y);
}

در نهایت، دستور return در offset 118 اجرا را از () به بخشی از JVM برمی‌گرداند که این متد را فراخوانی کرده است.

در مورد معنای بایت کد نگران نباشید

نکته مهم در این تمرین این است که ببینید تمام کدهای موجود در فهرست ۶ در فهرست ۶ مقداردهی اولیه فیلد و بلوک های مقداردهی اولیه کلاس در متد () قرار دارند و به ترتیب از بالا به پایین اجرا می شوند. .

چگونه اشیاء جاوا را مقداردهی اولیه کنیم

بعد از اینکه یک کلاس بارگذاری و مقداردهی اولیه شد، اغلب می خواهید اشیایی از کلاس ایجاد کنید. همانطور که در معرفی اخیر من برای برنامه نویسی با کلاس ها و اشیاء یاد گرفتید، یک شی را از طریق کدی که در سازنده کلاس قرار می دهید مقداردهی اولیه می کنید. فهرست ۷ را در نظر بگیرید.