내부 클래스란 클래스 내에 선언되는 클래스를 의미한다.
내부 클래스란 아래와 같이 클래스 안에 선언된 클래스를 말한다.
public class InnerClass {
class InnerClassTest{// 내부 클래스
...// 내부 클래스 내용
}
}
내부 클래스는 두 클래스가 매우 긴밀한 관계에 있는 경우 사용을 하며, 두 클래스간의 멤버에 서로 쉽게 접근이 가능하며, 외부에 추가적인 클래스를 노출하지 않아도 되서 코드의 복잡성을 줄이고 캡슐화가 가능하다는 장점이 있다.
내부 클래스는 선언 위치에 따라
인스턴스 클래스
,static 클래스
,지역 클래스
,익명 클래스
로 나뉜다.
내부 클래스는 선언 위치에 따라 인스턴스 클래스(instance class)
, static 클래스(static class)
, 지역 클래스(local class)
, 익명 클래스(anonymous class)
로 나뉜다.
public class InnerClass {
int val1=1;
float val2=2.0f;
class InstanceClass{// 인스턴스 클래스
public void changeOuter() {
val1=10;// 외부 클래스 값 변경
}
}
}
static
키워드가 붙은 클래스이다.정적(static) 멤버에만 접근할 수 있다.
public class InnerClass {
int val1=1;
float val2=2.0f;
static int staticVal=10;
static class StaticClass{// static 클래스
public void changeOuter() {
staticVal=5;
}
}
}
public class InnerClass {
int val1=1;
float val2=2.0f;
static int staticVal=10;
public void method(){
class LocalClass{// 지역 클래스
...// 내용
}
}
}
내부 클래스 역시 클래스이기 때문에 abstract
, final
과 같은 제어자를 사용할 수 있으며, 멤버변수들과 동일하게 private
, protect
과 같은 접근제어자 역시 사용할 수 있다.
또한 내부 클래스에서는 static class에서만 static
멤버를 선언할 수 있다.
class InnerClass {
class InstanceInner {
int iv = 100;
// static int cv = 100; // 에러! static변수를 선언할 수 없다.
final static int CONST = 100; // final static은 상수이므로 허용한다.
}
static class StaticInner {
int iv = 200;
static int cv = 200; // static클래스만 static멤버를 정의할 수 있다.
}
void myMethod() {
class LocalInner {
int iv = 300;
// static int cv = 300; // 에러! static변수를 선언할 수 없다.
final static int CONST = 300; // final static은 상수이므로 허용
}
}
public static void main(String args[]) {
System.out.println(InstanceInner.CONST); //100
System.out.println(StaticInner.cv); //200
}
}
output
100
200
익명 클래스는 이름이 없는 클래스로, 단 한번만 사용할 수 있는 일회용 클래스다.
익명클래스는 이름이 없는 클래스이기 때문에 일반 클래스처럼 생성자도 가질 수 없고, 단 한번만 사용되는 일회용 클래스이다.
객체지향은 클래스를 통해 객체화를 해서 클래스의 재사용성을 높이고, 확장 및 유지보수를 용의하게 하는데 중점이 되 있다. 모든것을 객체로 인식해 객체의 공통된 부분을 이용해 확장(상속)하고, 기능을 분류(인터페이스)해서 코드를 모듈화 하는것이 중요하다.
그러나, 익명클래스는 다르다. 같은 클래스
라는 이름을 갖고 있음에도 클래스의 재사용과 확장 및 상속을 고려하지 않고, 단 한번만 사용하는 클래스이다. 즉, 상속, 확장, 재사용성을 고려하지 않는다.
이런 클래스는 주로 프로그램에서 일시적으로 사용
되는 객체에 적용이 된다. 가령 우리가 화면을 만들때의 UI이벤트 처리, 스레드 객체 등 일시적인 경우에 사용이 된다.
예를 들어보자.
우리가 스마트폰에서 화면의 버튼을 클릭하는 이벤트 처리(버튼 클릭 감지)를 코딩한다 가정하자. 버튼이 눌리면 이벤트가 발생하면서 버튼이 눌렸습니다
라는 것을 표시한다고 하자. 그렇다면 이것을 클래스로 만들 수 있겠지만, 일반적으로 특정 버튼을 눌렀을때 특정 이벤트가 발생하는 것은 해당 이벤트에서만 발생하는 경우가 대부분이다. 이럴때는 굳이 클래스로 만들 필요가 없다는 것이다. 만약 버튼클릭을 객체지향으로 만든다면 이렇게 만들어야 할 것이다.
버튼 클릭이라는 공통된 클래스를 만들고, 각 버튼이 클릭되는 클래스를 상속하는 형식으로 만들면 객체지향적으로 설계가 되는 것이다.
그런데 생각해보자. 각 버튼간의 딱히 공통점도 없고, 해봐야 버튼이 클릭
됬다는 공통점만 있을 뿐인데 이렇게까지 복잡하게 설계할 필요가 있는가? 어쩌면 이렇게 객체지향
적으로 설계하면 유지보수만 귀찮아지고, 구조만 쓸데없이 복잡해진다.
이럴때 익명클래스를 이용하면 해당 버튼이 클릭
됬을때 사용하고 사라지기 때문에 버튼을 클릭하는 클래스를 유지보수할 필요가 없다. 왜냐하면 필요할때만 쓰고 없어지기 때문이다. 상속을 받는것도 아니기 때문에 클래스 관계도 신경쓸 필요가 없다.
스레드도 마찬가지이다. 스레드가 종료되면 해당 스레드의 객체는 필요가 없어진다. 마치, 우리가 워드로 작업을 하다가 워드를 종료하면 해당 워드 프로그램은 우리 화면에 남아있을 필요가 없는것 처럼 스레드 역시 스레드가 종료되면 스레드 객체는 사라진다. 즉, 필요할 때만 사용하고 사라지는 존재이기 때문에 굳이 클래스를 만들고, 상속을 하면서 객체지향적으로 설계할 필요가 없는 것이다. 오히려 객체지향적으로 설계하면 구조만 복잡해지고, 유지보수만 귀찮아질 뿐이다.
이처럼 익명클래스는 필요할 때만 사용되는 객체에서 주로 사용이 된다.
익명 클래스는 부모 클래스를 이용해 생성을 한다.
class Animal {
public String cry() {
return "동물이 웁니다";
}
}
public class Main {
public static void main(String[] args) {
Animal cat = new Animal() {// 익명클래스
@Override
public String cry() {
return "야옹";
}
}; // 익명클래스 끝에는 세미콜론 필요!
cat.cry();// 익명클래스 사용
}
}
위와 같이 부모클래스를 이용해 생성하고, 필요한 부분을 오버라이딩 해서 사용한다.
개발자로서 배울 점이 많은 글이었습니다. 감사합니다.