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");
});
}}
'Java공부(코딩)' 카테고리의 다른 글
코딩초보의 자바(Java)공부 22일차 { 예외처리 실습 } (0) | 2025.01.04 |
---|---|
코딩초보의 자바(Java)공부 21일차 { 예외처리 } (1) | 2025.01.03 |
코딩초보의 자바(Java)공부 20일차 { 중첩 클래스 , 내부클래스 1} (2) | 2025.01.02 |
코딩초보의 자바(Java)공부 19일차 { 날짜와 시간 } (3) | 2025.01.02 |
코딩초보의 자바(Java)공부 18일차 { 열거형 -ENUM - } (0) | 2024.12.31 |