class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
به این کلاس های داخلی تودرتو می گویند. آنها به 2 نوع تقسیم می شوند:
- کلاس های تو در تو غیر ایستا. به اینها طبقات داخلی نیز گفته می شود.
- کلاس های تو در تو استاتیک
- یک کلاس محلی
- یک کلاس ناشناس

public class Bicycle {
private String model;
private int weight;
public Bicycle(String model, int weight) {
this.model = model;
this.weight = weight;
}
public void start() {
System.out.println("Let's go!");
}
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left!");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
اینجا ما کلاس داریم Bicycle
. دارای 2 فیلد و 1 روش: start()
. 
Handlebar
و Seat
. کد آنها داخل کلاس نوشته شده است Bicycle
. اینها کلاس های کامل هستند: همانطور که می بینید، هر یک از آنها روش های خاص خود را دارند. در این مرحله، ممکن است این سوال برای شما پیش بیاید: چرا ما باید یک کلاس را در کلاس دیگر قرار دهیم؟ چرا آنها را کلاس های داخلی قرار دهیم؟ خوب، فرض کنید برای مفاهیم فرمان و صندلی در برنامه خود به کلاس های جداگانه نیاز داریم. البته لازم نیست ما آنها را تودرتو کنیم! ما می توانیم کلاس های معمولی بسازیم. به عنوان مثال، مانند این:
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
سوال خیلی خوبی! البته ما محدود به تکنولوژی نیستیم. انجام آن مطمئناً یک گزینه است. در اینجا نکته مهم بیشتر طراحی صحیح کلاس ها از منظر یک برنامه خاص و هدف آن است. کلاس های داخلی برای جدا کردن یک موجودیت است که به طور جدایی ناپذیری به موجودیت دیگری متصل است. فرمان، صندلی و پدال از اجزای دوچرخه هستند. جدا از دوچرخه، خیلی معنی ندارند. اگر همه این مفاهیم را در کلاسهای عمومی مجزا قرار میدادیم، کدی مانند این را در برنامه خود داشتیم:
public class Main {
public static void main(String[] args) {
Handlebar handlebar = new Handlebar();
handlebar.right();
}
}
هوم... توضیح معنای این کد حتی دشوار است. ما یک دسته فرمان مبهم داریم (چرا لازم است؟ صادقانه بگویم هیچ ایده ای ندارم). و این دستگیره به راست میچرخد...خود به خود بدون دوچرخه...به دلایلی. با جدا کردن مفهوم فرمان از مفهوم دوچرخه، منطقی را در برنامه خود از دست دادیم. با استفاده از یک کلاس داخلی، کد بسیار متفاوت به نظر می رسد:
public class Main {
public static void main(String[] args) {
Bicycle peugeot = new Bicycle("Peugeot", 120);
Bicycle.Handlebar handlebar = peugeot.new Handlebar();
Bicycle.Seat seat = peugeot.new Seat();
seat.up();
peugeot.start();
handlebar.left();
handlebar.right();
}
}
خروجی کنسول:
Seat up!
Let's go!
Steer left!
Steer right!
حالا چیزی که می بینیم ناگهان معنا پیدا می کند! :) ما یک شی دوچرخه درست کردیم. ما دو "موضوع" دوچرخه ایجاد کردیم - یک فرمان و یک صندلی. صندلی را برای راحتی بالا آوردیم و رفتیم: رکاب زدن و فرمان در صورت نیاز! :) متدهایی که ما نیاز داریم روی آبجکت های مناسب فراخوانی می شوند. این همه ساده و راحت است. در این مثال، جدا کردن فرمان و صندلی، کپسولاسیون را افزایش میدهد (دادههای مربوط به قطعات دوچرخه را در کلاس مربوطه پنهان میکنیم) و به ما امکان میدهد انتزاع دقیقتری ایجاد کنیم. حالا بیایید به یک وضعیت متفاوت نگاه کنیم. فرض کنید می خواهیم برنامه ای ایجاد کنیم که یک فروشگاه دوچرخه و قطعات یدکی دوچرخه را شبیه سازی کند. 
-
یک شی از یک کلاس داخلی نمی تواند بدون یک شی از یک کلاس بیرونی وجود داشته باشد.
این منطقی است: به همین دلیل است که ما کلاسهای داخلی
Seat
وHandlebar
کلاسهای درونی را در برنامه خود قرار دادیم - تا در نهایت با دستهها و صندلیهای یتیم مواجه نشویم.این کد کامپایل نمی کند:
public static void main(String[] args) { Handlebar handlebar = new Handlebar(); }
یکی دیگر از ویژگی های مهم از این نتیجه می شود:
-
یک شی از یک کلاس داخلی به متغیرهای کلاس خارجی دسترسی دارد.
به عنوان مثال، بیایید یک
int seatPostDiameter
متغیر (نماینده قطر پایه صندلی) بهBicycle
کلاس خود اضافه کنیم.سپس در
Seat
کلاس داخلی، میتوانیمdisplaySeatProperties()
متدی ایجاد کنیم که ویژگیهای seat را نمایش دهد:public class Bicycle { private String model; private int weight; private int seatPostDiameter; public Bicycle(String model, int weight, int seatPostDiameter) { this.model = model; this.weight = weight; this.seatPostDiameter = seatPostDiameter; } public void start() { System.out.println("Let's go!"); } public class Seat { public void up() { System.out.println("Seat up!"); } public void down() { System.out.println("Seat down!"); } public void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
و اکنون می توانیم این اطلاعات را در برنامه خود نمایش دهیم:
public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); Bicycle.Seat seat = bicycle.new Seat(); seat.displaySeatProperties(); } }
خروجی کنسول:
Seat properties: seatpost diameter = 40
توجه داشته باشید:متغیر جدید با سخت ترین اصلاح کننده دسترسی (
private
) اعلام می شود. و هنوز طبقه داخلی دسترسی دارد! -
یک شی از یک کلاس داخلی را نمی توان در روش ایستا یک کلاس خارجی ایجاد کرد.
این با ویژگی های خاص نحوه سازماندهی کلاس های داخلی توضیح داده می شود. یک کلاس داخلی می تواند سازنده هایی با پارامترها یا فقط سازنده پیش فرض داشته باشد. اما صرف نظر از اینکه، وقتی یک شی از یک کلاس داخلی ایجاد می کنیم، یک ارجاع به شیء کلاس خارجی به طور نامرئی به شی ایجاد شده از کلاس داخلی منتقل می شود. به هر حال، وجود چنین مرجع شی یک الزام مطلق است. در غیر این صورت، نمیتوانیم اشیایی از کلاس داخلی ایجاد کنیم.
اما اگر متدی از کلاس خارجی ثابت باشد، ممکن است شیئی از کلاس خارجی نداشته باشیم! و این نقض منطق نحوه عملکرد یک طبقه درونی خواهد بود. در این شرایط، کامپایلر یک خطا ایجاد می کند:
public static Seat createSeat() { // Bicycle.this cannot be referenced from a static context return new Seat(); }
-
یک کلاس داخلی نمی تواند شامل متغیرها و متدهای ثابت باشد.
منطق یکسان است: متدها و متغیرهای ایستا می توانند وجود داشته باشند و حتی در غیاب یک شی، فراخوانی یا ارجاع داده شوند.
اما بدون یک شی از کلاس خارجی، ما به کلاس داخلی دسترسی نخواهیم داشت.
یک تناقض آشکار! به همین دلیل است که متغیرها و متدهای استاتیک در کلاسهای داخلی مجاز نیستند.
اگر بخواهید آنها را ایجاد کنید کامپایلر یک خطا ایجاد می کند:
public class Bicycle { private int weight; public class Seat { // An inner class cannot have static declarations public static void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
-
هنگام ایجاد یک شی از یک کلاس داخلی، اصلاح کننده دسترسی آن مهم است.
یک کلاس داخلی را می توان با اصلاح کننده های دسترسی استاندارد علامت گذاری کرد:
public
,private
,protected
وpackage private
.چرا این مهم است؟
این روی جایی که میتوانیم نمونههایی از کلاس داخلی را در برنامه خود ایجاد کنیم، تأثیر میگذارد.
اگر
Seat
کلاس ما به صورت اعلان شودpublic
، می توانیمSeat
در هر کلاس دیگری اشیاء ایجاد کنیم. تنها شرط این است که یک شی از کلاس خارجی نیز باید وجود داشته باشد.به هر حال، ما قبلاً این کار را اینجا انجام دادیم:
public class Main { public static void main(String[] args) { Bicycle peugeot = new Bicycle("Peugeot", 120); Bicycle.Handlebar handlebar = peugeot.new Handlebar(); Bicycle.Seat seat = peugeot.new Seat(); seat.up(); peugeot.start(); handlebar.left(); handlebar.right(); } }
ما به راحتی
Handlebar
از کلاس به کلاس داخلی دسترسی پیدا کردیمMain
.اگر کلاس داخلی را به عنوان اعلان کنیم
private
، قادر خواهیم بود فقط در داخل کلاس خارجی اشیاء ایجاد کنیم.ما دیگر نمی توانیم یک
Seat
شی "در خارج" ایجاد کنیم:private class Seat { // Methods } public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); // Bicycle.Seat has private access in Bicycle Bicycle.Seat seat = bicycle.new Seat(); } }
احتمالا از قبل منطق را فهمیده اید :)
-
اصلاح کننده های دسترسی برای کلاس های داخلی مانند متغیرهای معمولی کار می کنند.
اصلاح
protected
کننده دسترسی به یک متغیر نمونه را در زیر کلاس ها و کلاس هایی که در یک بسته هستند فراهم می کند.protected
همچنین برای کلاس های داخلی کار می کند. می توانیمprotected
اشیایی از کلاس داخلی ایجاد کنیم:- در طبقه بیرونی؛
- در زیر کلاس های آن؛
- در کلاس هایی که در یک بسته هستند.
اگر کلاس داخلی یک اصلاح کننده دسترسی ( ) نداشته باشد
package private
، می توان اشیاء کلاس داخلی ایجاد کرد:- در طبقه بیرونی؛
- در کلاس هایی که در یک بسته هستند.
شما مدت زیادی است که با اصلاح کننده ها آشنا هستید، بنابراین مشکلی در اینجا وجود ندارد.
GO TO FULL VERSION