زبان برنامهنویسی جاوا به شما اجازه میدهد یک کلاس را داخل کلاس دیگری تعریف کنید. به چنین کلاسی Nested Class (کلاس تو در تو) گفته میشود و به این شکل نشان داده میشود:
class OuterClass {
...
class NestedClass {
...
}
}
اصطلاحشناسی: کلاسهای Nested به دو دسته تقسیم میشوند: غیراستاتیک و استاتیک. کلاسهای Nested غیراستاتیک Inner Class (کلاس داخلی) نامیده میشوند. کلاسهای Nested که static تعریف شدهاند Static Nested Class (کلاس Nested استاتیک) نام دارند.
class OuterClass {
...
class InnerClass {
...
}
static class StaticNestedClass {
...
}
}
Nested Class یکی از اعضای کلاس احاطهکنندهٔ خود محسوب میشود. Inner Classها (کلاسهای Nested غیراستاتیک) به سایر اعضای کلاس احاطهکننده دسترسی دارند، حتی اگر آن اعضا private تعریف شده باشند. Static Nested Classها به سایر اعضای کلاس احاطهکننده دسترسی ندارند. Nested Class بهعنوان عضوی از OuterClass میتواند با هر سطح دسترسی private، public، protected یا Package Private تعریف شود. به یاد داشته باشید که کلاسهای خارجی فقط میتوانند public یا Package Private تعریف شوند.
دلایل اصلی استفاده از Nested Classها عبارتند از:
A و B دارید که B به اعضایی از A نیاز دارد که در غیر این صورت private تعریف میشدند. با مخفیکردن کلاس B داخل کلاس A، اعضای A میتوانند private باشند و B همچنان به آنها دسترسی داشته باشد. علاوه بر این، خود B نیز از دید جهان بیرون پنهان میشود.مانند Methodها و متغیرهای Instance، یک Inner Class با یک نمونه از کلاس احاطهکننده پیوند دارد و به Methodها و فیلدهای آن شیء دسترسی مستقیم دارد.
اشیایی که نمونهای از Inner Class هستند، در داخل نمونهای از کلاس خارجی وجود دارند. کلاسهای زیر را در نظر بگیرید:
class OuterClass {
...
class InnerClass {
...
}
}
یک نمونه از InnerClass فقط میتواند در داخل نمونهای از OuterClass وجود داشته باشد و به Methodها و فیلدهای نمونهٔ احاطهکنندهاش دسترسی مستقیم دارد.
برای ایجاد نمونه از Inner Class، ابتدا باید نمونهای از کلاس خارجی ایجاد کنید. سپس شیء داخلی را داخل شیء خارجی با این ساختار بسازید:
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
دو نوع ویژه از Inner Class وجود دارد: Local Class (کلاس محلی) و Anonymous Class (کلاس بینام).
مانند Methodها و متغیرهای کلاس، Static Nested Class با کلاس خارجیاش پیوند دارد. و مانند Methodهای کلاس، Static Nested Class نمیتواند مستقیماً به متغیرها یا Methodهای Instance تعریفشده در کلاس احاطهکننده ارجاع دهد: فقط میتواند از طریق یک مرجع شیء از آنها استفاده کند. Inner Class and Nested Static Class Example این را نشان میدهد.
نکته: Static Nested Class با اعضای Instance کلاس خارجیاش (و سایر کلاسها) دقیقاً مانند هر کلاس سطح بالای دیگری تعامل دارد. در واقع، Static Nested Class از نظر رفتاری یک کلاس سطح بالاست که صرفاً به دلیل راحتی بستهبندی (Packaging)، داخل کلاس سطح بالای دیگری قرار گرفته است. Inner Class and Nested Static Class Example همچنین این را نشان میدهد.
برای ایجاد نمونه از Static Nested Class دقیقاً مانند کلاس سطح بالا عمل کنید:
StaticNestedClass staticNestedObject = new StaticNestedClass();
مثال زیر، OuterClass به همراه TopLevelClass، نشان میدهد که Inner Class (InnerClass)، Static Nested Class (StaticNestedClass) و کلاس سطح بالا (TopLevelClass) به کدام اعضای OuterClass دسترسی دارند:
public class OuterClass {
String outerField = "Outer field";
static String staticOuterField = "Static outer field";
class InnerClass {
void accessMembers() {
IO.println(outerField);
IO.println(staticOuterField);
}
}
static class StaticNestedClass {
void accessMembers(OuterClass outer) {
// خطای کامپایل: نمیتوان به فیلد non-static
// field outerField ارجاع Static داد
// IO.println(outerField);
IO.println(outer.outerField);
IO.println(staticOuterField);
}
}
public static void main(String[] args) {
IO.println("Inner class:");
IO.println("------------");
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
innerObject.accessMembers();
IO.println("\nStatic nested class:");
IO.println("--------------------");
StaticNestedClass staticNestedObject = new StaticNestedClass();
staticNestedObject.accessMembers(outerObject);
IO.println("\nTop-level class:");
IO.println("--------------------");
TopLevelClass topLevelObject = new TopLevelClass();
topLevelObject.accessMembers(outerObject);
}
}
public class TopLevelClass {
void accessMembers(OuterClass outer) {
// خطای کامپایل: نمیتوان به فیلد non-static
// OuterClass.outerField ارجاع Static داد
// IO.println(OuterClass.outerField);
IO.println(outer.outerField);
IO.println(OuterClass.staticOuterField);
}
}
خروجی این مثال:
Inner class:
------------
Outer field
Static outer field
Static nested class:
--------------------
Outer field
Static outer field
Top-level class:
--------------------
Outer field
Static outer field
توجه کنید که Static Nested Class با اعضای Instance کلاس خارجیاش دقیقاً مانند هر کلاس سطح بالای دیگری تعامل دارد. Static Nested Class StaticNestedClass نمیتواند مستقیماً به outerField دسترسی داشته باشد، چون این یک متغیر Instance از کلاس احاطهکننده OuterClass است. کامپایلر جاوا خطایی در دستور برجستهشده تولید میکند:
static class StaticNestedClass {
void accessMembers(OuterClass outer) {
// خطای کامپایل: نمیتوان به فیلد non-static
// field outerField ارجاع Static داد
IO.println(outerField);
}
}
برای رفع این خطا، به outerField از طریق یک مرجع شیء دسترسی پیدا کنید:
IO.println(outer.outerField);
بهطور مشابه، کلاس سطح بالا TopLevelClass نیز نمیتواند مستقیماً به outerField دسترسی داشته باشد.
اگر اعلامیهٔ نوعی (مانند متغیر عضو یا نام پارامتر) در یک دامنهٔ خاص (مانند Inner Class یا تعریف Method) نامی یکسان با اعلامیهٔ دیگری در دامنهٔ احاطهکننده داشته باشد، اعلامیهٔ داخلی اعلامیهٔ دامنهٔ احاطهکننده را سایهپوشانی (Shadow) میکند. نمیتوانید به اعلامیهٔ سایهپوشانیشده فقط با نامش ارجاع دهید. مثال زیر ShadowTest این را نشان میدهد:
public class ShadowTest {
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) {
IO.println("x = " + x);
IO.println("this.x = " + this.x);
IO.println("ShadowTest.this.x = " + ShadowTest.this.x);
}
}
public static void main(String... args) {
ShadowTest st = new ShadowTest();
ShadowTest.FirstLevel fl = st.new FirstLevel();
fl.methodInFirstLevel(23);
}
}
خروجی این مثال:
x = 23
this.x = 1
ShadowTest.this.x = 0
این مثال سه متغیر با نام x تعریف میکند: متغیر عضو کلاس ShadowTest، متغیر عضو Inner Class FirstLevel و پارامتر در Method methodInFirstLevel(). متغیر x که بهعنوان پارامتر Method methodInFirstLevel() تعریف شده، متغیر Inner Class FirstLevel را سایهپوشانی میکند. در نتیجه، وقتی از متغیر x در Method methodInFirstLevel() استفاده میکنید، به پارامتر Method ارجاع میدهد. برای ارجاع به متغیر عضو Inner Class FirstLevel، از کلمهٔ کلیدی this برای نمایش دامنهٔ احاطهکننده استفاده کنید:
IO.println("this.x = " + this.x);
برای ارجاع به متغیرهای عضوی که دامنههای بزرگتری را احاطه کردهاند، از نام کلاسی که به آن تعلق دارند استفاده کنید. برای مثال، دستور زیر به متغیر عضو کلاس ShadowTest از داخل Method methodInFirstLevel() دسترسی پیدا میکند:
IO.println("ShadowTest.this.x = " + ShadowTest.this.x);
Serialization کلاسهای داخلی (شامل Local Class و Anonymous Class) بهشدت توصیه نمیشود. وقتی کامپایلر جاوا ساختارهای خاصی مانند Inner Class را کامپایل میکند، ساختارهای مصنوعی (Synthetic Constructs) ایجاد میکند — اینها کلاسها، Methodها، فیلدها و سایر اجزایی هستند که معادلی در کد منبع ندارند. ساختارهای مصنوعی به کامپایلرهای جاوا اجازه میدهند ویژگیهای جدید زبان جاوا را بدون تغییر در JVM پیادهسازی کنند.
با این حال، ساختارهای مصنوعی ممکن است بین پیادهسازیهای مختلف کامپایلر جاوا متفاوت باشند، که یعنی فایلهای .class نیز ممکن است بین پیادهسازیهای مختلف متفاوت باشند. در نتیجه، ممکن است مشکلات سازگاری داشته باشید اگر Inner Class را Serialization کنید و سپس آن را با یک پیادهسازی JRE متفاوت Deserialization کنید.
برای دیدن Inner Class در عمل، ابتدا یک آرایه را در نظر بگیرید. در مثال زیر، یک آرایه ایجاد میکنید، آن را با مقادیر صحیح پر میکنید و سپس فقط مقادیر ایندکسهای زوج آرایه را به ترتیب صعودی چاپ میکنید.
مثال DataStructure.java زیر شامل بخشهای زیر است:
DataStructure که شامل یک Constructor برای ایجاد نمونهای از DataStructure حاوی آرایهای پرشده از مقادیر صحیح متوالی (۰، ۱، ۲، ۳ و...) و Methodای که عناصر آرایه با ایندکس زوج را چاپ میکند.EvenIterator که Interface DataStructureIterator را پیادهسازی میکند که خود از Interface Iterator<Integer> ارث میبرد. Iteratorها برای پیمایش یک ساختار داده استفاده میشوند و معمولاً Methodهایی برای بررسی عنصر آخر، بازیابی عنصر فعلی و حرکت به عنصر بعدی دارند.main که نمونهای از DataStructure (ds) ایجاد میکند و سپس Method printEven() را برای چاپ عناصر آرایه arrayOfInts با ایندکس زوج فراخوانی میکند.public class DataStructure {
// ایجاد آرایه
private final static int SIZE = 15;
private int[] arrayOfInts = new int[SIZE];
public DataStructure() {
// پرکردن آرایه با مقادیر صحیح صعودی
for (int i = 0; i < SIZE; i++) {
arrayOfInts[i] = i;
}
}
public void printEven() {
// چاپ مقادیر ایندکسهای زوج آرایه
DataStructureIterator iterator = this.new EvenIterator();
while (iterator.hasNext()) {
IO.print(iterator.next() + " ");
}
IO.println();
}
interface DataStructureIterator extends java.util.Iterator<Integer> { }
// Inner Class پیادهسازیکنندهٔ Interface DataStructureIterator
// که از Interface Iterator<Integer> ارث میبرد
private class EvenIterator implements DataStructureIterator {
// شروع پیمایش آرایه از ابتدا
private int nextIndex = 0;
public boolean hasNext() {
// بررسی اینکه آیا عنصر فعلی آخرین عنصر در آرایه است
return (nextIndex <= SIZE - 1);
}
public Integer next() {
// ثبت مقدار یک ایندکس زوج از آرایه
Integer retValue = Integer.valueOf(arrayOfInts[nextIndex]);
// دریافت عنصر زوج بعدی
nextIndex += 2;
return retValue;
}
}
public static void main(String s[]) {
// پرکردن آرایه با مقادیر صحیح و چاپ فقط
// مقادیر ایندکسهای زوج
DataStructure ds = new DataStructure();
ds.printEven();
}
}
خروجی:
0 2 4 6 8 10 12 14
توجه کنید که کلاس EvenIterator مستقیماً به متغیر Instance arrayOfInts شیء DataStructure ارجاع میدهد.
میتوانید از Inner Classها برای پیادهسازی کلاسهای کمکی مانند آنچه در این مثال نشان داده شد استفاده کنید. برای مدیریت رویدادهای رابط کاربری، باید نحوهٔ استفاده از Inner Classها را بدانید، چون مکانیزم مدیریت رویداد بهطور گسترده از آنها استفاده میکند.
دو نوع اضافی از Inner Class وجود دارد. میتوانید Inner Class را در داخل بدنهٔ یک Method تعریف کنید. این کلاسها به عنوان Local Class (کلاس محلی) شناخته میشوند. همچنین میتوانید Inner Class را در داخل بدنهٔ Method بدون نامگذاری تعریف کنید. این کلاسها به عنوان Anonymous Class (کلاس بینام) شناخته میشوند.
برای Inner Classها میتوانید از همان Modifierهایی استفاده کنید که برای سایر اعضای کلاس خارجی به کار میبرید. برای مثال، میتوانید از Specifierهای دسترسی private، public و protected برای محدودکردن دسترسی به Inner Classها استفاده کنید، دقیقاً همانطور که برای محدودکردن دسترسی به سایر اعضای کلاس استفاده میکنید.
Local Classها کلاسهایی هستند که در یک بلوک تعریف میشوند — بلوک گروهی از صفر یا چند دستور بین براکتهای متوازن است. معمولاً Local Classها را در داخل بدنهٔ یک Method پیدا میکنید.
این بخش موضوعات زیر را پوشش میدهد:
میتوانید Local Class را داخل هر بلوکی تعریف کنید (برای اطلاعات بیشتر عبارات، دستورات و بلوکها را ببینید). برای مثال، میتوانید Local Class را در بدنهٔ یک Method، حلقهٔ for یا بلوک if تعریف کنید.
مثال زیر LocalClassExample دو شماره تلفن را اعتبارسنجی میکند. این مثال Local Class به نام PhoneNumber را در Method validatePhoneNumber() تعریف میکند:
public class LocalClassExample {
static String regularExpression = "[^0-9]";
public static void validatePhoneNumber(
String phoneNumber1, String phoneNumber2) {
final int numberLength = 10;
// معتبر در JDK 8 و بالاتر:
// int numberLength = 10;
class PhoneNumber {
String formattedPhoneNumber = null;
PhoneNumber(String phoneNumber) {
// numberLength = 7;
String currentNumber = phoneNumber.replaceAll(
regularExpression, "");
if (currentNumber.length() == numberLength)
formattedPhoneNumber = currentNumber;
else
formattedPhoneNumber = null;
}
public String getNumber() {
return formattedPhoneNumber;
}
// معتبر در JDK 8 و بالاتر:
// public void printOriginalNumbers() {
// IO.println("Original numbers are " + phoneNumber1 +
// " and " + phoneNumber2);
// }
}
PhoneNumber myNumber1 = new PhoneNumber(phoneNumber1);
PhoneNumber myNumber2 = new PhoneNumber(phoneNumber2);
// معتبر در JDK 8 و بالاتر:
// myNumber1.printOriginalNumbers();
if (myNumber1.getNumber() == null)
IO.println("First number is invalid");
else
IO.println("First number is " + myNumber1.getNumber());
if (myNumber2.getNumber() == null)
IO.println("Second number is invalid");
else
IO.println("Second number is " + myNumber2.getNumber());
}
public static void main(String... args) {
validatePhoneNumber("123-456-7890", "456-7890");
}
}
این مثال شماره تلفن را با اول حذف تمام کاراکترها به جز ارقام ۰ تا ۹ اعتبارسنجی میکند. سپس بررسی میکند که آیا شماره تلفن دقیقاً ده رقم دارد (طول شماره تلفن در آمریکای شمالی). خروجی این مثال:
First number is 1234567890
Second number is invalid
Local Class به اعضای کلاس احاطهکنندهاش دسترسی دارد. در مثال قبلی، Constructor PhoneNumber() به عضو LocalClassExample.regularExpression دسترسی دارد.
علاوه بر این، Local Class به متغیرهای محلی نیز دسترسی دارد. با این حال، Local Class فقط میتواند به متغیرهای محلی دسترسی داشته باشد که final تعریف شده باشند. وقتی Local Class به متغیر محلی یا پارامتر بلوک احاطهکننده دسترسی پیدا میکند، آن متغیر یا پارامتر را Capture میکند. برای مثال، Constructor PhoneNumber() به متغیر محلی numberLength دسترسی دارد، چون final تعریف شده است؛ numberLength یک متغیر Capture شده است.
با این حال، از Java SE 8 به بعد، Local Class میتواند به متغیرها و پارامترهای محلی بلوک احاطهکنندهاش که final یا Effectively Final هستند دسترسی داشته باشد. متغیر یا پارامتری که مقدارش پس از مقداردهی اولیه هرگز تغییر نکرده باشد، Effectively Final است. برای مثال، فرض کنید متغیر numberLength final تعریف نشده و شما دستور تخصیص برجستهشده را در Constructor PhoneNumber() اضافه میکنید تا طول شماره تلفن معتبر را به ۷ رقم تغییر دهید:
PhoneNumber(String phoneNumber) {
numberLength = 7;
String currentNumber = phoneNumber.replaceAll(
regularExpression, "");
if (currentNumber.length() == numberLength)
formattedPhoneNumber = currentNumber;
else
formattedPhoneNumber = null;
}
به دلیل این دستور تخصیص، متغیر numberLength دیگر Effectively Final نیست. در نتیجه، کامپایلر جاوا پیام خطایی مشابه «متغیرهای محلی ارجاعشده از Inner Class باید final یا effectively final باشند» تولید میکند، آنجا که Inner Class PhoneNumber سعی در دسترسی به متغیر numberLength دارد:
if (currentNumber.length() == numberLength)
از Java SE 8 به بعد، اگر Local Class را در یک Method تعریف کنید، میتواند به پارامترهای Method دسترسی داشته باشد. برای مثال، میتوانید Method زیر را در Local Class PhoneNumber تعریف کنید:
public void printOriginalNumbers() {
IO.println("Original numbers are " + phoneNumber1 +
" and " + phoneNumber2);
}
Method printOriginalNumbers() به پارامترهای phoneNumber1 و phoneNumber2 Method validatePhoneNumber() دسترسی دارد.
اعلامیهٔ نوعی (مانند متغیر) در Local Class، اعلامیههای مشابه در دامنهٔ احاطهکننده را سایهپوشانی میکند. برای اطلاعات بیشتر بخش Shadowing را ببینید.
Local Classها شبیه Inner Classها هستند چون نمیتوانند عضو Static تعریف یا اعلام کنند. Local Classها در Methodهای Static (مانند کلاس PhoneNumber که در Method Static validatePhoneNumber() تعریف شده) فقط میتوانند به اعضای Static کلاس احاطهکننده ارجاع دهند. برای مثال، اگر متغیر عضو regularExpression را به عنوان static تعریف نکنید، کامپایلر جاوا خطایی مشابه «متغیر non-static regularExpression نمیتواند از بافت Static ارجاع داده شود» تولید میکند.
Local Classها non-static هستند چون به اعضای Instance بلوک احاطهکننده دسترسی دارند. در نتیجه، نمیتوانند حاوی اکثر انواع اعلامیههای Static باشند.
نمیتوانید Interface را داخل یک بلوک اعلام کنید — Interfaceها ذاتاً Static هستند. برای مثال، قطعه کد زیر کامپایل نمیشود چون Interface HelloThere در داخل بدنهٔ Method greetInEnglish() تعریف شده است:
public void greetInEnglish() {
interface HelloThere {
public void greet();
}
class EnglishHelloThere implements HelloThere {
public void greet() {
IO.println("Hello " + name);
}
}
HelloThere myGreeting = new EnglishHelloThere();
myGreeting.greet();
}
نمیتوانید Initializer Static یا Interface عضو در Local Class اعلام کنید. قطعه کد زیر کامپایل نمیشود چون Method EnglishGoodbye.sayGoodbye() static اعلام شده. کامپایلر خطایی مشابه «Modifier static فقط در اعلامیهٔ متغیر Constant مجاز است» تولید میکند وقتی با این تعریف Method مواجه شود:
public void sayGoodbyeInEnglish() {
class EnglishGoodbye {
public static void sayGoodbye() {
IO.println("Bye bye");
}
}
EnglishGoodbye.sayGoodbye();
}
Local Class میتواند عضو Static داشته باشد به شرطی که متغیر Constant باشند. (متغیر Constant متغیری از نوع Primitive یا String است که final تعریف شده و با یک عبارت Compile-Time Constant مقداردهی اولیه شده باشد. عبارت Compile-Time Constant معمولاً یک رشته یا عبارت ریاضی است که در زمان کامپایل قابل ارزیابی است.) قطعه کد زیر کامپایل میشود چون عضو Static EnglishGoodbye.farewell یک متغیر Constant است:
public void sayGoodbyeInEnglish() {
class EnglishGoodbye {
public static final String farewell = "Bye bye";
public void sayGoodbye() {
IO.println(farewell);
}
}
EnglishGoodbye myEnglishGoodbye = new EnglishGoodbye();
myEnglishGoodbye.sayGoodbye();
}
---
Anonymous Classها به شما اجازه میدهند کد مختصرتری بنویسید. آنها تعریف و نمونهسازی کلاس را همزمان ممکن میکنند. مشابه Local Class هستند اما نام ندارند. اگر فقط یکبار به Local Class نیاز دارید از Anonymous Class استفاده کنید.
Local Classها اعلامیهٔ کلاس هستند، اما Anonymous Classها عبارت (Expression) هستند — یعنی کلاس را داخل عبارت دیگری تعریف میکنید. مثال زیر HelloWorldAnonymousClasses از Anonymous Class در عبارات مقداردهی اولیهٔ متغیرهای محلی frenchGreeting و spanishGreeting استفاده میکند، اما برای مقداردهی اولیهٔ متغیر englishGreeting از Local Class استفاده میکند:
public class HelloWorldAnonymousClasses {
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
public void sayHello() {
class EnglishGreeting implements HelloWorld {
String name = "world";
public void greet() {
greetSomeone("world");
}
public void greetSomeone(String someone) {
name = someone;
IO.println("Hello " + name);
}
}
HelloWorld englishGreeting = new EnglishGreeting();
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
IO.println("Salut " + name);
}
};
HelloWorld spanishGreeting = new HelloWorld() {
String name = "mundo";
public void greet() {
greetSomeone("mundo");
}
public void greetSomeone(String someone) {
name = someone;
IO.println("Hola, " + name);
}
};
englishGreeting.greet();
frenchGreeting.greetSomeone("Fred");
spanishGreeting.greet();
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp =
new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
همانطور که قبلاً ذکر شد، Anonymous Class یک عبارت است. ساختار نحوی عبارت Anonymous Class شبیه فراخوانی Constructor است، با این تفاوت که تعریف کلاس در یک بلوک کد وجود دارد.
نمونهسازی شیء frenchGreeting را در نظر بگیرید:
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
IO.println("Salut " + name);
}
};
عبارت Anonymous Class شامل اجزای زیر است:
newHelloWorld را پیادهسازی میکند.frenchGreeting را نمونهسازی میکند. (این توضیح میدهد چرا پس از براکت پایانی نقطهٔویرگول وجود دارد.)مانند Local Classها، Anonymous Classها میتوانند متغیرها را Capture کنند؛ دسترسی یکسانی به متغیرهای محلی دامنهٔ احاطهکننده دارند:
final یا Effectively Final تعریف نشدهاند دسترسی داشته باشد.Anonymous Classها همچنین همان محدودیتهای Local Classها را در مورد اعضایشان دارند:
توجه کنید که در Anonymous Classها میتوانید موارد زیر را اعلام کنید:
نکته: اما در Anonymous Class نمیتوانید Constructor اعلام کنید.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/