코딩 기록들
자바의 다양한 기능들 1. 여러 내부클래스 본문
1.여러 내부 클래스의 정의와 유형
내부클래스
- 중첩클래스 라고도 함
- 클래스 내부에 클래스를 선언 -> 클래스 내부에서만 사용 (외부에서 사용 못하게 하기 위함 -> 주로 내부클래스는 private로 선언함)
- 내부클래스의 종류 : 인스턴스 내부 클래스, 정적(static) 내부 클래스, 지역(local->함수 안에서 사용 ) 내부 클래스, 익명(anonymous-> 변수에는 없는내용, 현업에서 가장 많이 활용되는 클래스) 내부 클래스
인스턴스 내부클래스
- 내부적으로 사용할 클래스를 선언 (private으로 선언 권장)
- 외부 클래스가 생성된 후 생성됨 ( 정적 내부 클래스와 다름 )
- private이 아닌 내부 클래스는 다른 외부 클래스에서 생성할 수 있음
- static변수를 내부에 사용할수없음 : 외부클래스 생성과 상관없이 쓸수있는게 static 변수이므로, 인스턴스 이너클래스 내부에서는 정적변수(static) 사용할수 없다 : 정적변수는 정적내부클래스에서 사용해야됨
class OutClass {
private int num = 10;
private static int sNum = 20;
private InClass inClass;
public OutClass(){
inClass = new InClass(); // 내부 클래스 생성
}
private class InClass{
int inNum = 100;
//static int sInNum = 200; //에러 남
void inTest(){
System.out.println("OutClass num = " +num + "(외부 클래스의 인스턴스 변수)");
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수)");
System.out.println("InClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수)");
}
//static void sTest(){ //에러 남
//}
}
public void usingClass(){
inClass.inTest(); //내부 클래스 변수를 사용하여 메서드 호출하기
}
}
public class InnerTest {
public static void main(String[] args) {
// 1. 가장 많이 쓰는 방법
OutClass outClass = new OutClass();
System.out.println("외부 클래스 이용하여 내부 클래스 기능 호출");
outClass.usingClass(); // 내부 클래스 기능 호출
System.out.println();
// 2. private이 아닌 경우 이렇게 외부에서도 생성은 가능함
OutClass.InClass inClass = outClass.new InClass(); // 외부 클래스를 이용하여 내부 클래스 생성하는 방법
System.out.println("외부 클래스 변수를 이용하여 내부 클래스 생성"); // 윗줄처럼 불러왔을때, 이너에대한 intest메서드 호출가능
inClass.inTest();
}
}
정적 내부 클래스
- 정적클래스의 일반메서드에서 외부 클래스의 인스턴스 변수는 사용할수없다 (정적클래스가 외부클래스와 상관없이 만들어질수 있으므로 ) -> 본인의 인스턴스변수는 쓸수있음
- 정적클래스의 정적메서드에서는 static변수만 (내,외부로) 사용할수있다
// 정적 내부 클래스
static class InStaticClass{
int inNum = 100;
static int sInNum = 200;
void inTest(){ //정적 클래스의 일반 메서드
//num += 10; // 외부 클래스의 인스턴스 변수는 사용할 수 없음.
System.out.println("InStaticClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수 사용)");
System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
}
static void sTest(){ // 정적 클래스의 static 메서드
//num += 10; // 외부 클래스의 인스턴스 변수는 사용할 수 없음.
//inNum += 10; // 내부 클래스의 인스턴스 변수는 사용할 수 없음
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");
}
}
}
public class InnerTest {
public static void main(String[] args) {
.....
//외부 클래스 생성하지 않고 바로 정적 내부 클래스 생성
// 일반메소드
OutClass.InStaticClass sInClass = new OutClass.InStaticClass();
System.out.println("정적 내부 클래스 일반 메서드 호출");
sInClass.inTest();
System.out.println();
// static 메소드 : 바로 호출 가능
// 클래스 생성들하고 무관하게 정적메서드는 바로 호출될수 있음(이땐, static변수만 쓸수있다)
System.out.println("정적 내부 클래스의 스태틱 메소드 호출");
OutClass.InStaticClass.sTest();
}
}
지역 내부 클래스
- 메서드 내부에 정의하여 사용하는 클래스, 클래스를 메서드 내부에서 생성하고 사용 -> 여기에서 이름을 없애버린게 익명내부클래스
- 메서드의 호출이 끝나면 메서드에 사용된 지역변수의 유효성은 사라짐
- 외부 지역변수 사용시 주의할점 : 메서드 호출 이후에도 사용해야 하는 경우가 있을 수 있으므로 지역 내부 클래스에서 사용하는 메서드의 지역 변수나 매개 변수는 final로 선언됨 (final로 선언된 변수는 상수메모리에 잡힘 ->= 상수가 됨 = 값을 바꿀 수 없다)
- 매개변수는 메소드가 호출될 때 생성됨 (스택메모리에 생성) -> 메소드 호출이 끝나고 나면, 로컬변수와 메소드변수는 없어짐 / 메소드는 또 호출이 될 여지가 있으므로, 지역내부클래스에서 사용하는 메서드 안에 있는 변수는 사라질수 도 있으므로, final로 선언해줘야함
class Outer{
int outNum = 100;
static int sNum = 200;
Runnable getRunnable(int i){
int num = 100;
class MyRunnable implements Runnable{
int localNum = 10;
@Override
public void run() {
//num = 200; //에러 남. 지역변수는 상수로 바뀜
//i = 100; //에러 남. 매개 변수 역시 지역변수처럼 상수로 바뀜
System.out.println("i =" + i);
System.out.println("num = " +num);
System.out.println("localNum = " +localNum);
System.out.println("outNum = " + outNum + "(외부 클래스 인스턴스 변수)");
System.out.println("Outter.sNum = " + Outer.sNum + "(외부 클래스 정적 변수)");
}
}
return new MyRunnable();
}
}
public class LocalInnerTest {
public static void main(String[] args) {
Outer out = new Outer();
Runnable runner = out.getRunnable(10);
runner.run();
}
}
위 코드에서 myRunnable 이라는 클래스 이름은 메소드 안 외에 다른 곳에서 쓸 일이 없음 -> 이 메소드에서만 쓰는 클래스이름을 없애버림 : runner-inner 클래스
class Outer{
int outNum = 100;
static int sNum = 200;
Runnable getRunnable(int i){
int num = 100;
return new Runnable(){ //**요렇게 이름을 없애주고 바로 리턴값을 준다!
int localNum = 10;
@Override
public void run() {
//num = 200; //에러 남. 지역변수는 상수로 바뀜
//i = 100; //에러 남. 매개 변수 역시 지역변수처럼 상수로 바뀜
System.out.println("i =" + i);
System.out.println("num = " +num);
System.out.println("localNum = " +localNum);
System.out.println("outNum = " + outNum + "(외부 클래스 인스턴스 변수)");
System.out.println("Outter.sNum = " + Outer.sNum + "(외부 클래스 정적 변수)");
}
}
}
//익명 내부 클래스
Runnable runnable = new Runnable(){
@Override
public void rin() {
System.out.println("Runnable class")
}
}
익명 내부 클래스
- 이름이 없는 일회용 클래스 (위 지역 내부 클래스의 MyRunnable 클래스 이름은 실제로 호출되는 경우가 없음)
- 정의와 생성을 동시에 함
- 클래스의 이름을 생략하고 주로 하나의 인터페이스나 하나의 추상 클래스를 구현하여 반환해주는 일을 제일 많이 함
- 인터페이스나 추상 클래스 자료형의 변수에 직접 대입하여 클래스를 생성하거나 지역 내부 클래스의 메서드 내부에서 생성하여 반환 할 수 있음
- 안드로이드) widget 이벤트 핸들러에 활용됨
- 컴파일하고나면 이름이 숫자로 뜸(이름이 없으므로)
new 조상클래스이름 () {
// 멤버선언
}
new 구현 인터페이스 이름 () {
// 멤버선언
}
'Java' 카테고리의 다른 글
[자바의 다양한 기능들] 6-2. 예외처리하기와 미루기(2) (1) | 2024.01.09 |
---|---|
자바의 다양한 기능들 5. 패키지 여행비용 계산하기 예제(스트림 활용) (1) | 2024.01.09 |
자바의 다양한 기능들 4. reduce() (1) | 2024.01.09 |
자바의 다양한 기능들 3.스트림 Stream (1) | 2024.01.07 |
자바의 다양한 기능들 2. 함수형 프로그래밍과 람다식 Lamada expression (0) | 2024.01.04 |