class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
이러한 내부 클래스를 중첩이라고 합니다. 두 가지 유형으로 나뉩니다.
- 비정적 중첩 클래스. 내부 클래스라고도 합니다.
- 정적 중첩 클래스.
- 지역 수업
- 익명 클래스

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()
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