클래스 내부에 클래스를 선언하여 외부 클래스의 필드 접근에 용이하기 위함.
우리가 클래스를 다른 클래스 밖에서 쓰려면 그 클래스의 소속을 알려주어야 했다. (객체화)
내부 클래스의 필드를 사용하기 위해서는 외부 클래스에서 내부 클래스를 객체화 해야한다.
외부클래스명 객체명 = new 외부클래스생성자();
외부클래스명.내부클래스명 객체명 = 외부클래스객체명.new 내부클래스 생성자();
(해석 : 외부 클래스 안의 내부클래스 타입의 객체를 선언할건데, 이미 메모리에 올라가있는 외부클래스객체 안에 내부클래스의 생성자가 있기 때문에 new을 붙인다.)
주문이 들어와야 배달을 한다.
주문을 할 때 사용자의 주소,품목,전화번호가 전부 주문 클래스에 있을 것.
배달 클래스는 주문클래스 안에 있는 필드를 써야 할 것인데, 다른 데서 쓰지도 않는데도 자꾸 객체화를 해야할 것이다.
A클래스에서 b라는 작업이 자주 쓰이고, 이 작업은 B 클래스를 만들어야 쉽게 관리할 수 있음. 하지만 다른 클래스에서 b 작업이 필요 없거나(A클래스에서만 필요하거나), B클래스를 외부에 노출시키고 싶지 않을 때 캡슐화를 사용한다.
내부클래스를 외부클래스 안에 가둬놓은 다음, "나만 쓸거야!" 하는 거다.
내부 클래스는 GUI(Graphic User Interface)개발시 많이 사용됨.
예를 들어 a라는 버튼과 b라는 버튼이 있다고 하자. 두 버튼의 기능이 서로 다르다면 클래스를 별도로 만드는 것보다 내부 클래스로 만들어 사용하는 것이 적합할 것. 각각 클래스로 놓기에는 다른 데에서는 무쓸모인 것.
외부 클래스(OutClass) 안에 내부 클래스(innerClass)를 만들어보자.
package innerClass;
public class OutClass {
int outData;
public OutClass() {
System.out.println("외부 클래스 생성자 호출됨.");
}
public void showOuter() {
System.out.println("외부 클래스의 메서드 호출됨.");
}
public class innerClass {
int inData;
public innerClass() {
System.out.println("내부 클래스의 생성자 호출됨.");
}
public void showInner() {
outData = 20;
System.out.println("내부 클래스의 메서드 호출됨.");
System.out.println("outData : " + outData);
// 내부에서 값을 변경한 것.
showOuter();
// 외부의 메서드도 사용이 된다.
} // 내부에서 외부에 접근을 하고 있는 것. 외부 필드를 사용할 때 굉장히 용이하구나.
}
// 한 페이지에서는 public class는 하나만 있어야한다 했다.
// Outclass와 InnerClass는 현재 동격이 아니다.
// InnerClass는 Outclass의 소속인 것. 얘도 하나의 필드로 쳐서
// 각 접근권한 제어자를 붙일 수 있다.
// Outclass가 크기 때문에 메인클래스로 인식이 된다.
public static void main(String[] args) {
OutClass out = new OutClass();
// 출력값 : 외부 클래스 생성자 호출됨.
OutClass.innerClass in = out.new innerClass();
// 출력값 : 내부 클래스의 생성자 호출됨.
// 내부클래스에 접근하는 방법이다.
in.showInner();
// 출력값 :
//내부 클래스의 메서드 호출됨.
//outData : 20
//외부 클래스의 메서드 호출됨.
}
}
이름이 없는 클래스(일회성으로 사용하기 위함)
안드로이드에서 아주 많이 자주 쓰이는 문법
package anonyClass;
public interface Cafe {
//메뉴판
//판매
void setMenu(String[] menu);
String[] getMenu();
void sell(String choice);
// 전부 앞에 abstract가 생략되어 있다.
}
main으로 가보자
package anonyClass;
public class Starbucks {
private String[] menu = {"아메리카노", "레몬티", "카푸치노"};
private int[] arPrice = {5000, 8000, 9000};
private int income;
String choice;
public String[] getMenu() {
return menu;
}
public void setMenu(String[] menu) {
this.menu = menu;
}
public int[] getArPrice() {
return arPrice;
}
public void setArPrice(int[] arPrice) {
this.arPrice = arPrice;
}
public int getIncome() {
return income;
}
public void setIncome(int income) {
this.income = income;
}
// 외부에서 인터페이스 타입 Cafe로 받아옴. 등록하는 메서드이기 때문에
// 매번 재정의하는 인터페이스 타입으로 받아온 것임.
public void registCafe(Cafe c, String choice) {
c.setMenu(menu);
System.out.println("카페 등록 완료");
System.out.println("----Menu----");
for (int i = 0; i < c.getMenu().length; i++) {
System.out.println(i+1+ "." +c.getMenu()[i]);
// 1.아메리카노 2.레몬티 3.카푸치노
}
c.sell(choice);
}
public static void main(String[] args) {
Starbucks gangnam = new Starbucks();
gangnam.registCafe(new Cafe() {
// 인터페이스라서 재정의해주어야 함. 값이기 때문에 이름이 없는 상태
// 매번 사용할 때마다 재정의해주어야 하는 애들은 이렇게 익명클래스로 사용된다.
// 다시 사용할게 아니니까.
@Override
public void setMenu(String[] menu) {
gangnam.menu = menu;
}
@Override
public void sell(String choice) {
for (int i = 0; i < gangnam.getMenu().length; i++) {
if(gangnam.getMenu()[i].equals(choice)) {
gangnam.income += gangnam.arPrice[i];
}
}
}
@Override
public String[] getMenu() {
return gangnam.menu;
}
},"카푸치노");
// (,)콤마 앞까지가 new Cafe의 매개변수
System.out.println("카푸치노 주문 완료");
System.out.println("현재 수익 : " + gangnam.getIncome() + "원" );
}
}
출력 결과
카페 등록 완료
----Menu----
1.아메리카노
2.레몬티
3.카푸치노
카푸치노 주문 완료
현재 수익 : 9000원