در اینجا همه چیزهایی است که باید در مورد مقداردهی اولیه کلاس ها و اشیاء جاوا قبل از اجرای آنها در 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 برمیگرداند که این متد را فراخوانی کرده است.
در مورد معنای بایت کد نگران نباشید
نکته مهم در این تمرین این است که ببینید تمام کدهای موجود در فهرست ۶ در فهرست ۶ مقداردهی اولیه فیلد و بلوک های مقداردهی اولیه کلاس در متد
قرار دارند و به ترتیب از بالا به پایین اجرا می شوند. .
چگونه اشیاء جاوا را مقداردهی اولیه کنیم
بعد از اینکه یک کلاس بارگذاری و مقداردهی اولیه شد، اغلب می خواهید اشیایی از کلاس ایجاد کنید. همانطور که در معرفی اخیر من برای برنامه نویسی با کلاس ها و اشیاء یاد گرفتید، یک شی را از طریق کدی که در سازنده کلاس قرار می دهید مقداردهی اولیه می کنید. فهرست ۷ را در نظر بگیرید.
پست های مرتبط
مقداردهی اولیه کلاس و شی در جاوا
مقداردهی اولیه کلاس و شی در جاوا
مقداردهی اولیه کلاس و شی در جاوا