Java공부(코딩)

코딩초보의 자바(Java)공부 20일차 { 중첩클래스 , 내부클래스 2 }

동곤일상 2025. 1. 2. 23:15
반응형

2025.01.02 - [Java공부(코딩)] - 코딩초보의 자바(Java)공부 20일차 { 중첩 클래스 , 내부클래스 1}

 

코딩초보의 자바(Java)공부 20일차 { 중첩 클래스 , 내부클래스 1}

오늘은 중첩클래스 , 내부클래스에대해서 알아보겠습니다!!!중첩 for문이 있듯이클래스도 중첩으로 만들 수 있어요!중첩 클래스의 분류중첩 클래스는 크게는 2가지작게는 4가지로 나뉩니다.   

ddkk1120.tistory.com

 

이 내용과 이어집니다!!! 


지역 클래스

 

지역클래스는 내부클래스의 특별한 종류중 하나임.

그러므로 바깥클래스의 인스턴스멤버 접근 가능

지역 클래스 예

class Outer {
	public void process() {
	//지역 변수
	int localVar = 0;
	//지역 클래스
	class Local {...}
	Local local = new Local();
	}
}

지역클래스 예제1

public class LocalOuterV1 {
	private String outInstanceF = "바깥클래스 필드";
	
	public void process(int param) {
		String localF = "바깥클래스의 지역 변수";
		
		class LocalPrint{
			String F = "지역클래스의 변수";
			
			public void printData() {
				System.out.println("F : "+F);
				System.out.println("localF : "+localF);
				System.out.println("param : "+param);
				System.out.println("outInstacneF : "+outInstanceF);
			}
		}
        //이곳은 process 메서드 내부임
		LocalPrint localPrint = new LocalPrint();
		localPrint.printData();	
	}
	public static void main(String[] args) {
		LocalOuterV1 localOuterV1 = new LocalOuterV1();
		localOuterV1.process(99);}
       }

 

출력

F : 지역클래스의 변수

localF : 바깥클래스의 지역 변수

param : 99

outInstacneF : 바깥클래스 필드


지역클래스 예제2

당연한 얘기겠지만 지역클래스도 일반 클래스처럼

인터페이스를 구현하거나 부모를상속받을 수 있음.

 

public interface Printer {
	void print();}

 

public class LocalOuterV2 {
	private String outInstanceF = "바깥클래스 필드";

	public void process(int param) {
		String localF = "바깥클래스의 지역 변수";

		class LocalPrint implements Printer{
			String F = "지역클래스의 변수";
			@Override
			public void print() {
				System.out.println("F : "+F);
				System.out.println("localF : "+localF);
				System.out.println("param : "+param);
				System.out.println("outInstacneF : "+outInstanceF);

			}	
		}
		LocalPrint localPrint = new LocalPrint();
		localPrint.print();

	}
	public static void main(String[] args) {
		LocalOuterV1 localOuterV1 = new LocalOuterV1();
		localOuterV1.process(99);

	}

}

implements Printer로 

Printer인터페이스를 상속받고

메서드를 오버라이딩해

정상 사용되는 모습!!

 


익명클래스

익명 클래스는 말그대로

이름이 없는 클래스다!!

 

지역 클래스의 선언과 생성**
```java
	//선언
	class LocalPrinter implements Printer{
	//body
	}
	//생성
	Printer printer = new LocalPrinter();
익명 클래스 - 지역 클래스의 선언과 생성을 한번에**
```java
Printer printer = new Printer(){
	//body
	}

 

 

예제를 통해 만들어보자 !!

package nested.anonymous;

 

import nested.local.Printer;

 

public class AnonymousOuter {

private int outInstance = 1;

 

public void process(int param) {

int localVar = 2;

Printer a = new Printer() {

 

@Override

public void print() {

}

};

 

Printer printer = new Printer() {

int value = 3;

 

@Override

public void print() {

System.out.println("value : "+value);

System.out.println("localF : "+localVar);

System.out.println("param : "+param);

System.out.println("outInstacneF : "+outInstance);

}};

printer.print();

System.out.println("printer.class : "+printer.getClass());

System.out.println("printerA.class : "+a.getClass());

{

}

}

public static void main(String[] args) {

AnonymousOuter anonymousOuter = new AnonymousOuter();

anonymousOuter.process(6);

 

}}

 

value : 3

localF : 2

param : 6

outInstacneF : 1

printer.class : class nested.anonymous.AnonymousOuter$2

printerA.class : class nested.anonymous.AnonymousOuter$1

 

Printer printer = new Printer() {

로 익명클래스를 생성

 

생성법

`new` 다음에 바로 상속 받으면서 구현 부모 타입을 입력하면 된다.

코드는 마치 인터페이스 `Printer` 생성하는 처럼 보인다. 하지만 자바에서 인터페이스를 생성하는 것을 불가

능하다. 코드는 인터페이스를 생성하는 것이 아니고, `Printer` 라는 이름의 인터페이스를 구현한 익명 클래스를

성하는 것이다. `

 

익명 클래스 특징

익명 클래스는 이름 없는 지역 클래스를 선언하면서 동시에 생성한다.

**익명 클래스는 부모 클래스를 상속 받거나, 또는 인터페이스를 구현해야 한다.** 익명 클래스를 사용할 때는 상위

래스나 인터페이스가 필요하다.

익명 클래스는 그대로 이름이 없다. 이름을 가지지 않으므로, 생성자를 가질 없다. (기본 생성자만 사용됨)

익명 클래스는 `AnonymousOuter$1` 같이 자바 내부에서 바깥 클래스 이름 + `$` + 숫자로 정의된다. 익명

래스가 여러개면 `$1` , `$2` , `$3`

으로 숫자가 증가하면서 구분된다.

 

 

 

**익명 클래스를 사용할 없을 **

익명 클래스는 번만 인스턴스를 생생할 있다. 다음과 같이 여러 생성이 필요하다면 익명 클래스를 사용할

없다. 대신에 지역 클래스를 선언하고 사용하면 된다.

 


익명클래스 활용 예제

 

리팩토링 전
```java
package nested.anonymous.ex;
import java.util.Random;
public class Ex1Main {
public static void helloDice() {
System.out.println("프로그램 시작");
//코드 조각 시작
int randomValue = new Random().nextInt(6) + 1;
System.out.println("주사위 = " + randomValue);
//코드 조각 종료
System.out.println("프로그램 종료");
}
public static void helloSum() {
System.out.println("프로그램 시작");
//코드 조각 시작
for (int i = 1; i <= 3; i++) {
System.out.println("i = " + i);
}
//코드 조각 종료
System.out.println("프로그램 종료");
}
public static void main(String[] args) {
helloDice();
helloSum();
}
}

 

출력

프로그램 시작

주사위 = 5 //랜덤

프로그램 종료

프로그램 시작

i = 1

i = 2

i = 3

프로그램 종료

 

 

익명클래스활용

 

package nested.anonymous.ex;

 

import java.util.Random;

 

public class Ex1_RefMain {

static int a;

private static void hello(Process process) {

System.out.println("프로그램 시작");

process.run();

System.out.println("프로그램 종료\n");

 

}

public static void main(String[] args) {

Process dice = new Process() {

 

@Override

public void run() {

a=new Random().nextInt(6)+1;

System.out.println("주사위 : "+a);

 

}

};

Process sum = new Process() {

 

@Override

public void run() {

int sum = 0;

for (int i = 0; i <= a; i++) {

sum+=i

System.out.print(i);

if(i != a) { //a가 아닐때만 + 붙이기

System.out.print("+");

}

}System.out.println("\n주사위의 합 : "+sum);

 

}

};

hello(dice);

hello(sum);

}}

 

프로그램 시작

주사위 : 3

프로그램 종료

 

프로그램 시작

0+1+2+3

주사위의 합 : 6

프로그램 종료

 

일단 저는 주사위숫자를 바깥클래스의 정적변수로 정해두고

그 숫자를 모두가공유함으로써

1부터 주사위나온숫자만큼의 합까지 

구해보는 메서드를 추가하였습니다!!

 

또한 익명클래스를 활용해

보다 간편하게 만들었습니다.

(참고로 익명클래스는 인터페이스가

꼭 있어야함)

 

이코드를 그대로 이용해서

ㄷ익명클래스의

또다른 활용을 보여드릴게요


익명클래스는 참조를직접 전달할수 있습니다.

(변수에 담아둘필요없음)

 

코드로 보시죠!!

package nested.anonymous.ex;

 

import java.util.Random;

 

public class Ex1_RefMain {

static int a;

private static void hello(Process process) {

System.out.println("프로그램 시작");

process.run();

System.out.println("프로그램 종료\n");

 

}

public static void main(String[] args) {

hello(new Process() {

 

@Override

public void run() {

a=new Random().nextInt(6)+1;

System.out.println("주사위 : "+a);

 

}

});

 

 

hello(new Process() {

 

@Override

public void run() {

int sum = 0;

for (int i = 0; i <= a; i++) {

sum+=i;

System.out.print(i);

if(i != a) {

System.out.print("+");

}

 

 

 

}System.out.println("\n주사위의 합 : "+sum);

 

}

});

}

 

}

hello(new Process() {

 

@Override

public void run() {

a=new Random().nextInt(6)+1;

System.out.println("주사위 : "+a);

}

});

이렇게 참조값을 변수에 담아둘 필요없이 바로 사용가능


람다(lamda)

자바8 이전까지 메서드에 인수로 전달할 있는 것은 크게 2가지였다.

1)`int` , `double` 같은 기본형 타입

2)`Process` `Member` 같은 참조형 타입(인스턴스)

결국 메서드에 인수로 전달할 있는 것은 간단한 데이터나, 인스턴스의 참조이다.

 

자바8 들어서면서 변화가 있었는데 바로 메서드( 정확히는 함수) 인수로 전달할 있게 되었다. 이것을 간단

람다(Lambda) 한다.

이때 메서드는 (static == 정적) 이어야함

 

public class Ex1_RefMainRamda {

static int a;

private static void hello(Process process) {

System.out.println("프로그램 시작");

process.run();

System.out.println("프로그램 종료\n");

 

}

public static void main(String[] args) {

hello(()->{

a = new Random().nextInt(6)+1;

System.out.println("주사위 : "+a);

});

 

hello(()-> {

int sum = 0;

for (int i = 1; i <= a; i++) {

sum+=i;

System.out.print(i);

if(i != a) {

System.out.print("+");

}

 

 

}System.out.println("\n주사위의 합 : "+sum);

});

}}

 

hello(()->{

a = new Random().nextInt(6)+1;

System.out.println("주사위 : "+a);

});

이런식으로 메서드를 생성하지않고

바로 전달을 할 수가 있다

(메서드의 코드블럭만 전달)

 

메서드는 꼭 static이어야함


문제1 - 정적 중첩 클래스를 완성해라

`

package nested.test;
public class OuterClass1 {
// 여기에 NestedClass를 구현해라. 그리고 hello() 메서드를 만들어라.
}
package nested.test;
public class OuterClass1Main {
public static void main(String[] args) {
// 여기에서 NestedClass의 hello() 메서드를 호출하라.
}
}

 

 

풀이

public class OuterClass1 {

int value= 10;

 

static class NestedClass1{

public void hello() {

System.out.println(NestedClass1.class);

System.out.println("NestedClass1의 메서드 hello");

}}}

 

public class OuterClassMain1 {

 

public static void main(String[] args) {

NestedClass1 nested = new OuterClass1.NestedClass1();

nested.hello();

 

NestedClass1 nestedClass1 = new NestedClass1(); //이게 왜 되지??????

nestedClass1.hello();

}}

 

출력

class nested.nested.test.OuterClass1$NestedClass1

NestedClass1의 메서드 hello

class nested.nested.test.OuterClass1$NestedClass1

NestedClass1의 메서드 hello

 


문제2 - 내부 클래스를 완성해라

package nested.test;
public class OuterClass2 {
// 여기에 InnerClass를 구현해라. 그리고 hello() 메서드를 만들어라.
}
package nested.test;
public class OuterClass2Main {
public static void main(String[] args) {
// 여기에서 InnerClass의 hello() 메서드를 호출해라.
}
}

public class OuterClass2 {

String value= "바깥클래스의 인스턴스변수";

 

class InnerClass{

public void hello() {

System.out.println(InnerClass.class);

System.out.println("InnerClass의 메서드 hello");

System.out.println(value);

 

}}}

 

mport nested.finaltest.OuterClass2.InnerClass;

 

public class OuterClassMain2 {

 

public static void main(String[] args) {

OuterClass2 outerClass2 = new OuterClass2();

InnerClass innerClass = outerClass2.new InnerClass();

innerClass.hello();

}}

 

출력

class nested.finaltest.OuterClass2$InnerClass

InnerClass의 메서드 hello

바깥클래스의 인스턴스변수


문제3 - 지역 클래스를 완성해라

 

package nested.test;
class OuterClass3 {
public void myMethod() {
// 여기에 지역 클래스 LocalClass를 구현하고 hello() 메서드를 호출해라.
}
}
package nested.test;
class OuterClass3Main {
public static void main(String[] args) {
OuterClass3 outerClass3 = new OuterClass3();
outerClass3.myMethod();
}
}

 

 

풀이

public class OuterClass3 {

String outerInstance = "바깥인스턴스 변수";

 

public void myMethod() {

class LocalClass{

void hello() {

System.out.println(LocalClass.class);

System.out.println("LocalClass의 메서드 hello");

System.out.println(outerInstance+"접근가능");

}

}

LocalClass localClass = new LocalClass();

localClass.hello();

}}


문제4 - 익명 클래스를 완성해라

package nested.test;
public interface Hello {
void hello();
}
package nested.test;
class AnonymousMain {
public static void main(String[] args) {
// 여기에서 Hello의 익명 클래스를 생성하고 hello()를 호출해라.
}
}

 

풀이

public class AnonymousMain {

 

public static void main(String[] args) {

Hello a = new Hello() {

 

@Override

public void hello() {

System.out.println("Hello.hello");

 

}

};a.hello();

System.out.println(a.getClass());}

}

 

 

2번째 풀이법(람다 활용)

public class AnonymousMain_ramda {

 

public static void ramda(Hello hello) { //전달받는 메서드는 꼭 static!!!!!!

hello.hello();

}

 

public static void main(String[] args) {

ramda(()->{

System.out.println("Hello.hello");

 

});

}}