내부클래스 (Inner Class)
내부클래스의 필요성
- 내부 클래스는 다른 클래스 내부에 작성되는 클래스를 말한다.
- 내부 클래스에서는 외부 클래스 멤버 접근 제한자와 무관하게 접근할 수 있다.
- 내부 클래스를 사용하면 다른 곳에서는 사용되지 않는 클래스를 내부에 감춤으로써 프로그램의 복잡도를 감소시킬 있다.
[예시]
객체지향 프로그램의 출발점은 추상화를 거쳐 현실 세계의 객체를 분석하고 클래스를 만드는 일이다.
분석 과정에서 관리해야할 요소 들의 성격에 따라 여러개의 클래스가 도출 될 수 있다.
스마트폰을 시스템을 프로그래밍한다고 생각해보자.
스마트폰에는 전화, 베터리, 와이파이, GPS 기능이 있다.
스마트폰 시스템에 대해 프로그래밍 설계도를 짜보면
첫번째 생각 : 모든 기능은 스마트폰 안에 있으므로 SmartPhone 클래스 안에 모든 기능을 담는다.
첫번째 생각-장점 : 내부에 모든 기능이 있으므로 클래스 접근 제한자에 구애받지 않고 편하게 기능들을 담을 수 있다.
첫번째 생각-단점 : 그러나 모듈화가 되지 않기때문에 클래스의 복잡도가 올라가고, 유지보수에 좋지 않다.
두번째 생각 : 전화, 베터리, 와이파이,GPS 기능을 여러 클래스로 분리해서 모듈화 한다.
두번째 생각-장점 : 모듈화를하면 클래스가 간결해지고 유지보수하기 편하다.
'두번째 생각'이 더 좋아 보이므로 SmartPhone 클래스에서 Battery, GPS, WIFI를 멤버변수(has-a)로 관리해보자.
package SmartPhone;
public class SmartPhone {
private Battery battery=new Battery();
private GPSModule gps=new GPSModule(new Battery());
private WiFiModule wifi=new WiFiModule();
}
public class GPSModule {...}
public class WiFiModule {...}
public class Battery {...}
GPS를 사용하면 Battery의 잔량이 줄어드는 GPSModule을 설계해보자.
같은 SmartPhone 안에 있었으면 상관 없지만 클래스가 달라졌기 때문에 Battery에 접근하기 위해서는 Battery의 참조값이 필요하다. 따라서 아래와 같은 코드가 나온다.
public class GPSModule {
Battery battery;
public GPSModule(Battery battery) {
this.battery=battery;
}
public void useBattery() {
//gps를 쓸때마다 잔량이 5만큼 줄어든다.
battery.useBattery(5);
}
}
사실 GPS는 다른곳(대리점, 과금정보 확인 등)에서 사용할 일이 없다.
위처럼 has-a관계에 있는 클래스 내부에서만 사용되는 클래스를 만들 때는 내부 클래스(inner class)를 활용하는 것을 고려할만 하다.
public class SmartPhone {
private Battery battery=new Battery();
private GPSModule gps=new GPSModule();
private WiFiModule wifi=new WiFiModule();
//GPSModule을 내부클래스로 구현
public class GPSModule {
public void useBattery{
battery.useBattery(5);
}
}
}
내부 클래스로 작성해주면 SmartPhone의 private 멤버 변수인 battery를 마치 자신의 멤버 변수처럼 사용할 수 있다.
내부클래스의 종류
내부 클래스는 선언되는 위치와 형태에 따라 다음과 같은 4가지로 구분된다.
인스턴스 내부 클래스
<인스턴스 내부 클래스를 작성할때 주의 사항>
- 인스턴스 내부 클래스는 외부 클래스의 멤버 변수 선언 위치에 static 키워드 없이 선언된 클래스를 말한다.
- 내부 클래스에서 외부 클래스의 멤버에 접근할 때 private를 포함한 모든 멤버에 대해 자유롭게 참조할 수 있다.
- 인스턴스 내부 클래스는 static 멤버를 가질 수 없다.
단, static final 멤버는 상수로 취급되므로 예외로 사용할 수 있다.
<객체 생성시 static 메서드 영역과 인스턴트 메서드 영역에서의 방법이 다르다>
- static 영역에서 인스턴스 내부 클래스의 객체를 만들 때는
먼저 외부 클래스의 객체를 만들고, 이를 통해서 내부 클래스의 객체를 생성한다. - non-static 영역에서 객체를 만들 때는 바로 객체의 생성이 가능하다.
package nested;
public class InstanceInnerTest {
//인스턴스 내부 클래스 설정
class Inner{
int innerMember=10;
//The field staticMember cannot be declared static in a non-static inner type,
//unless initialized with a constant expression
//static int staticMember=10;
static final int finalStaticMember=10;
private void innerMethod() {
System.out.println("om : "+outerMember+", im : "+ innerMember);
}
}
//외부 멤버 변수
private int outerMember=10;
//인스턴스 메서드 영역에서 인스턴스 내부 클래스의 객체 생성
private void outerMethod() {
Inner inner=new Inner();
inner.innerMember=100;
inner.innerMethod();
}
//클래스 메서드 영역에서 인스턴스 내부 클래스의 객체 생성
public static void main(String[] args) {
InstanceInnerTest iit=new InstanceInnerTest();
Inner inner=iit.new Inner();
inner.innerMethod();
}
}
<inner class의 멤버와 외부 클래스의 멤버 간의 이름 충돌로 인해 정확히 소속을 밝혀야할 경우가 있다.>
- 내부 클래스에서 내부클래스의 멤버를 참조 할때, 'this' 사용
- 내부 클래스에서 외부클래스의 멤버를 참조 할때, '외부클래스.this' 사용
public class DuplicatedNameTest {
private int num=100;
class InnerClass{
private int num=200;
public void method() {
//아무런 소속 없이 사용된 num은 가장 가까운데 선언된 내부 클래스의 num을 참조한다.
System.out.println(num); //200
//내부 클래스에서 명시적으로 사용된 this는 자신의 참조 값을말하므로 역시 내부 클래스의 num을 의미한다.
System.out.println(this.num); //200
//외부클래스에 선언된 멤버 변수 num을 사용하기 위해 DuplicatedNameTest.this를 사용한다.
System.out.println(DuplicatedNameTest.this.num); //100
}
}
public static void main(String[] args) {
DuplicatedNameTest dnt=new DuplicatedNameTest();
InnerClass ic=dnt.new InnerClass();
ic.method();
}
}
<전혀 별개의 클래스에서 인스턴스 내부 클래스를 생성할 때>
- 외부 클래스의 레퍼런스를 확보하고, 이 레퍼런스를 통해서 내부 클래스를 생성해야한다.
- 주의점! 같은 패키지임에도 불구하고 import문이 필요하다.
나중에 코드 추가
클래스 내부 클래스
<특징>
클래스 내부 클래스는 static 키워드가 붙은 내부 클래스이다
(일반 클래스는 클래스를 선언할 때 static 키워드를 사용할 수 없다.)
클래스 내부 클래스
로컬 내부 클래스(Local Inner Class)
익명의 내부 클래스(Anonymous Inenr Class)
람다식
람다식이란?
다양한 형태의 람다식
람다식을 이용한 함수형 프로그래밍
Consumer 계열
Supplier 계열
Funtion 계열
Operator 계열
Predicate 계열
'JAVA' 카테고리의 다른 글
I/O (Input/Output) (0) | 2019.12.12 |
---|---|
예외(Exception)처리 / 로깅(logging) / 디버깅(debugging) (0) | 2019.12.11 |
추상클래스(Abstract Class) / 인터페이스(Interface) (0) | 2019.12.09 |
클래스의 관계-상속/제어자/다형성/패키지/임포트 (0) | 2019.12.08 |
클래스(class)와 객체(object, instance) (0) | 2019.12.01 |