2023. 3. 30. 20:58ㆍjava
1. Exception try~catch문
try ~catch문은 catch절을 여러 번 사용 가능
조건으로 자식 예외 클래스부터 catch해야됨
예로 => RuntimeException을 API로 보면
상위클래스 Object에서 하위클래스로 RuntimeException까지 볼 수 있다.
여기서 Exception을 catch절에서 맨 아래에 위치시키고 하위 클래스인 RuntimeException을 상단에 위치시켜야 한다.
만약 Exception보다 아래에 catch문이 있다면 그 catch문은 도달할 수 없다는 에러가 뜨게 되면서 위치를 수정시켜야 된다.
Exception으로 에러를 다 잡을 수 있으나 메시지가 하나라 어떤 에러가 났는지 정확히는 모른다.
Exception으로도 세분화된 메시지를 보내기 위함은, if문에 instanceOf로 메시지를 세분화시킬 수 있다.
package exception21;
import java.util.InputMismatchException;
import java.util.Scanner;
public class ExceptionCatch {
/*
-catch절을 여러개 사용할 수 있다
-여러개 사용시 자식 예외클래스부터 catch해야한다
-부모 예외 클래스를 자식 예외 클래스보다 상위에
위치시켜 놓으면 부모가 예외를 모두 잡아버리기
때문에
자식예외클래스의 catch절에는
unreacheable catch block이되어
컴파일이 안된다.
*/
public static void main(String[] args) {
Scanner sc= new Scanner(System.in);
int[] arr= new int[2];
try {
System.out.println("arr[0]에 입력할 숫자?");
String firstStr=sc.nextLine();
arr[0]=Integer.parseInt(firstStr);
System.out.println("arr[1]에 입력할 숫자?");
arr[1]=sc.nextInt();
System.out.println("두 숫자 나누기:"+arr[0]/arr[1]);
}
/*
아래처럼 여러개의 catch불락 사용시 부모 예외클래스는
항상 맨 아래에 위치 시켜라
catch(Exception e) {
System.out.println("예외가 발생했어요");
}*/
catch(NumberFormatException e) {
System.out.println("arr[0]은 숫자만 입력하세요");
}
catch(InputMismatchException e) {
System.out.println("arr[1]은 숫자만 입력하세요");
}
catch(ArithmeticException e) {
System.out.println("0으로 나눌수 없어요");
}
/*
모든 예외를 catch(Exception e)블락 하나로 다 잡을 수
있으나
각각의 예외 클래스별로 예외처리를 세분화하기
힘들다는 단점이 있다.*/
catch(Exception e) {
/*
if(e instanceof NumberFormatException) {
System.out.println("arr[0]에는 숫자만 입력하세요");
}*/
System.out.println("예외가 발생했어요");
}
}/////////class
}/////////main
2. finally절
try~catch~finally를 쓰던 try~finally를 쓰던 finally는 실행한다.
ex) DB연결을 만약 했다면 끊는 용도로 쓴다.
DB를 계속 연결상태 유지하면 그만큼 메모리를 잡아먹고 있는 것
단, System.exit(0);를 만나면 시스템 종료.
외부 자원 사용 시 예외 클래스들 처리방법
1. 직접 하지 말고 throws를 통해 던지자
2. try~catch문을 사용
런타임 에러는 무조건 try~catch를 사용
ExceptionFinal.java
package exception21;
import java.io.IOException;
import java.util.InputMismatchException;
import java.util.Scanner;
/*
finally절:예외가 발생하든 안하든 반드시 실행 하고자하는 명령문들을 기술.
1) try ~catch절
-예외 직접 처리
2) try ~catch~finally절
-예외 직접 처리후 반드시 실행할 문장도 처리
3) try ~finally절
-예외는 던지고(throws) 예외가 발생하든 안하든 반드시 실행할 문장 처리
※ finally절안에 있는 명령문은
return문을 만나더라도 실행됨,
단,System.exit(0)를 만나면 당연히 실행안됨.
*/
/*
[1.외부 자원 사용시 발생하는 예외 클래스들(컴파일 예외) 처리 방법]
1-1. 직접 처리하지 말고 던지자
해당 메소드명 옆에 throws 예외클래스명
1-2. 예외를 개발자가 직접 처리 try~catch절 이용
try{
예외가 발생할 만한 코드
}
catch(예외클래스 인스턴스변수){
예외발생시 catch절에서 처리
}
※try는 단독으로 못쓰고
try~catch 혹은
try~finally절 혹은
try~catch~finally의 쌍으로 사용한다.
※런타임예외는 던져봤자 의미 없다.
반드시 try~catch절로 직접 처리해야 한다
※main메소드에서는 런타임 예외는 반드시 try~catch
컴파일예외는 던지거나 try~catch해도 됨.
*/
public class ExceptionFinally {
//컴파일 예외 발생하는 메소드]
static void compile() throws IOException {
System.out.println("한 문자를 입력하세요?");
//방법1]예외를 던진다
int ascii= System.in.read();
System.out.println("입력한 문자:"+(char)ascii);
//방법2]직접 try~catch로 처리(다른 메소드에서 예외처리 불필요)
/*
try {
int ascii= System.in.read();
System.out.println("입력한 문자:"+(char)ascii);
}catch(IOException e) {e.printStackTrace();}
*/
}////////
static void tryFinally() throws IOException {
try {
compile();
}
finally {
System.out.println("반드시 실행할 명령문");
}
}////////////
//런타임 예외 발생하는 메소드]
static void runTime() {
Integer.parseInt("백억원");
}
static void tryCatchFinally() {
Scanner sc= new Scanner(System.in);
int age=-10;
try {
System.out.println("나이를 입력하세요?");
age=sc.nextInt();
//return;//테스트시 정상적 숫자 입력-finally절 실행
System.exit(0);//테스트시 정상적 숫자 입력-finally절 실행안되고 프로그램 종료
}
catch(InputMismatchException e) {
System.out.println("나이는 숫자만");
}
finally {
//아래는 예외가 발생하든 안하든 무조건 출력하자
System.out.println("당신의 10년후 나이:"+(age+10));
}
}
public static void main(String[] args) /*throws IOException*/ /*throws NumberFormatException*/ {
//컴파일 예외는 던지거나 try~catch하거나]
//1]던지거나
//compile();
//2]try~catch하거나
try {
compile();
}
catch(IOException e) {e.printStackTrace();}
//런타임 예외는 반드시 try~catch]
try {
runTime();
}
catch(Exception e) {
System.out.println("숫자형식이 아니예요:"+e.getMessage());
}
tryCatchFinally();
}/////////main
}//////////////class
3. ExceptionThrows
예외 객체 생성 후 throw키워드로 직접 던지기
반환타입은 throw를 사용
throws를 이용해서 던진 예외는 언젠가 try~catch로 처리해야 한다.
계속 던졌다면 최종 main에서는 다시 던질 수 있겠지만 실행 시 에러나 뜸.
결국 try~catch 해야 된다.
Exception e = new Exception("짝수는 안돼요"); 예외 객체 생성
뒤 throw e;쓰면 메소드 옆에 thows를 써줘야 된다.
ExceptionThrows.java
package exception21;
import java.io.IOException;
/*
예외객체 생성후 throw키워드를 이용해서 직접 던지기
- 반환타입 메소드명 throws 예외클래스와 쌍이다.
- throws를 이용해서 던진 예외는 언젠가는 반드시
try~catch를
해야 한다. 즉 만약 계속 던졌다면
최종 main에서는 다시 던질 수는 있지만
실행시 에러 고로
try~catch해야 한다.
형식]
접근지정자 [modifier] 반환타입 메소드명 throws 예외클래스{
특정조건일때
throw new Exception();
//throw 이후의 명령문은 실행이 안된다.
}
*/
public class ExceptionThrows {
/*
기존 자바에서 제공해주는 예외를 던지는 메소드(예:read()) 호출하는 경우]
*/
static void throwsMethodByJava() throws IOException{/*throws IOException를 지우면 아래 read()에 빨간줄 생김*/
System.out.println("문자 입력?");
System.in.read();
}////////
static void callByJava() throws IOException{//throwsMethodByJava()가 있어서 또 던지던가 try~catch문사용해야됨
throwsMethodByJava();
}
static void throwsMethodByUser(int value) throws Exception{
if(value %2==0) {
//1.예외객체 생성
Exception e= new Exception("짝수는 안돼요");
throw e;
//System.out.println("throw 키워드 이후");//[x]unreachable code에러 발생
}
System.out.println(value+"는 홀수");
}
static void callByUser(int value) throws Exception {
throwsMethodByUser(value);
}
public static void main(String[] args) /*throws IOException */{
//callByJava();//예외를 던져도 되고 try~catch해도 된다
try {
callByUser(10);
}
catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
4. 내가 만든 Exception
NotGoodAppearanceException.java / Club.java / ClubApp.java
4-1) NotGoodAppearanceException.java
package exception21;
//1]Exception클래스를 상속받아 예외클래스로 만든다.
public class NotGoodAppearanceException extends Exception{
//2]생성자 정의
//[기본 생성자]
public NotGoodAppearanceException() {
//Exception의 인자 생성자인 Exception(String message) 호출]
//인자인 message는 getMessage()로 호출할때 반환되는 예외 메시지임
super("복장 불량은 입장불가");
}
//[인자 생성자]
public NotGoodAppearanceException(String message) {
super(message);
}
}
4-2) Club.java
package exception21;
public class Club {
void entrance(String clothes,int age) throws NotGoodAppearanceException {
if("남루".equals(clothes)) {
throw new NotGoodAppearanceException();
}
else if("정장".equals(clothes) && age < 20)
throw new NotGoodAppearanceException("나이가 너무 어려요");
else if("정장".equals(clothes) && age > 40)
throw new NotGoodAppearanceException("나이가 너무 많아요");
System.out.println("입장하세요....즐....");
}
}
4-3) ClubApp.java
package exception21;
public class ClubApp {
public static void main(String[] args) {
Club club= new Club();
try {
club.entrance("남루", 20);
}
catch (NotGoodAppearanceException e) {
System.out.println(e.getMessage());
}
try {
club.entrance("정장", 15);
}
catch (NotGoodAppearanceException e) {
System.out.println(e.getMessage());
}
try {
club.entrance("정장", 45);
}
catch (NotGoodAppearanceException e) {
System.out.println(e.getMessage());
}
try {
club.entrance("정장", 20);
}
catch (NotGoodAppearanceException e) {
System.out.println(e.getMessage());
}
}//////////////////////main
}//////////////class
5. 내부 클래스
원래 클래스에 static이 안 붙음 하지만 클래스 안에 클래스는 static이 붙을 수 있음.
지금 17 버전으로 하고 있는데 16 버전부터 static이 붙은 정적 멤버도 가질 수 있게 됨.
정적멤버에 그냥 클래스명. 하고 접근 가능
외부클래스에서는 내부 클래스 멤버 접근 불가
외부클래스에서 내부 클래스 접근하려면 내부클래스 인스턴스화하고 접근 가능
하지만, 외부 정적 메소드에서 내부 정적 멤버 인스턴스화 없이 접근 가능.
bin파일에서 Inner클래스는 외부클래스$내부클래스.class로 나타남
그래서 같은 패키지에 같은 클래스 이름 안되지만 외부클래스$내부클래스여서
내부클래스 이름이 같아도 외부클래스로 달라서 구별가능
내부에서 외부에 접근 방법
일단, 내부 클래스에서 this는 내부클래스를 뜻함.
그럼 외부 클래스접근은 외부클래스.this.변수명하면 외부 멤버 변수를 뜻하게 됨
내부에서 외부를 접근하는데 static이 붙은 메소드는 저번에 배웠듯이 static은 JVM에서 classLoad에서 생성됨.
그러니 인스턴스객체는 new연산자 사용할 때 (인터프리터때-mian을 찾음) 생성돼서 호출이 불가능.
별도의 다른 클래스에서는 내부 클래스를 인스턴스화 불가
=> main도 다른 클래스(InnerMemberClass)에 속함 그러니 인스턴스화 불가
접근방법
1. 외부클래스를 인스턴스화한 후 접근=> 내부 클래스 인스턴스 접근=> 내부클래스의 멤버 변수에 접근 도달
2. 외부클래스에서 내부 클래스를 인스턴스 안 한 경우
=> 외부클래스명. 내부클래스명 변수 = 외부클래스인스턴스.new 내부클래스명()으로 내부클래스 인스턴스화
InnerMemberClass.java
package innerclass22;
import innerclass22.OuterClass.InnerClass;
/*
[내부 멤버 클래스]:클래스안의 클래스로 static이 안붙음
- 외부클래스의 모든 멤버(정적이든 인스턴스형이든)를 사용할 수있다.
- 정적멤버는 가질 수 없다.(JDK 15까지만)
- 단,JDK 16부터는 정적 멤버도 가질 수 있게 되었다.
JDK 16이후 부터는 제약이 없어졌다.
그래서 외부클래스와 별개의 다른 클래스에서도 외부 클래스 인스턴스화 없이
내부의 정적 멤버에 접근 할 수 있게 되었다.
- 외부클래스명$내부클래스명.class로 파일이 생긴다.
- 이벤트 기반 프로그래밍( GUI프로그래밍):윈도우 프로그래밍,웹프로그래밍,모바일 프로그래밍등
시 주로 사용
※외부클래스에서 내부클래스의 멤버 접근에 관한 이론
-외부클래스에서는 내부 클래스의 멤버 접근 불가
-외부 클래스에서 내부 클래스의 멤버에 접근하려면
내부 클래스를 인스턴스화 한 후에 접근할 수 있다
단,외부의 정적 메소드에서는 내부의 정적멤버만 인스턴스화 없이
내부클래스명.정적멤버로 접근가능
그러나 내부 클래스의 정적 상수는 내부 클래스명으로 접근가능.
*/
class OuterClass {
// 멤버 변수
int outerInstanceVar;
int sameVar;
static int outerStaticVar;
//내부 클래스 인스턴스화 하기]
InnerClass inner = new InnerClass();
// 멤버 메소드
void outerInstanceMethod() {
//[외부에서 내부로 접근하기]
//외부에서는 내부의 멤버에 접근 불가(접근하려면 반드시 내부 클래스를 인스턴스화 해야한다)
//System.out.println(innerInstanceVar);//[x]
//innerInstanceMethod();//[X]
System.out.println(inner.innerInstanceVar);//[o]
inner.innerInstanceMethod();//[o]
}///////
static void outerStaticMethod() {
//[외부에서 내부로 접근하기]
//내부의 정적 멤버[o]:내부클래스명.정적멤버
System.out.println(InnerClass.innerStaticVar);//[o]
InnerClass.innerStaticMethod();//[o]
System.out.println();//////////////////
}//////////
// [내부 멤버 클래스]
class InnerClass {
//[멤버 변수]
int innerInstanceVar;
int sameVar = 1;
static int innerStaticVar;//JDK16이전버전까지는 컴파일 에러
// [생성자]
public InnerClass() {
System.out.println("내부의 클래스의 생성자");
}
//[멤버 메소드]
void innerInstanceMethod() {
//[내부에서 외부에 접근하기]
//※내부 클래스에서는 외부의 모든 멤버 사용 가능
System.out.println(outerInstanceVar);
System.out.println(outerStaticVar);
outerInstanceMethod();
outerStaticMethod();
//※외부의 멤버 와 내부 멤버 충돌할때
//내부 클래스안에서 this는 내부 클래스 지칭
//내부 클래스안에서 외부클래스명.this는 외부 클래스를 지칭
//내부 멤버변수 = 내부 멤버변수
//this.sameVar=sameVar;
//※외부 멤버변수 = 내부 멤버변수
OuterClass.this.sameVar=sameVar;
}
static void innerStaticMethod() {
//[내부에서 외부에 접근하기]
//외부의 정적멤버만 사용가능
//System.out.println(outerInstanceVar);//[x]
System.out.println(outerStaticVar);//[o]
//outerInstanceMethod();//[x]
outerStaticMethod();//[o]
}
}//////////
}//////////
public class InnerMemberClass {
public static void main(String[] args) {
//별도의 다른 클래스에서는 내부클래스 인스턴스화 불가
//InnerClass inClass = new InnerClass();//[x]
//1]외부 클래스를 인스턴스화 한다(필수)
OuterClass outerClass=new OuterClass();
//방법1]외부 클래스에서 내부클래스를 인스턴스 한 경우
System.out.println(outerClass.inner.innerInstanceVar);
//방법2]외부 클래스에서 내부클래스르 인스턴스화 하지 않은 경우
//외부클래스명.내부클래스명 변수 = 외부클래스인스턴스변수.new 내부클래스명()으로
//내부클래스 인스턴스화
OuterClass.InnerClass inner= outerClass.new InnerClass();
System.out.println(inner.innerInstanceVar);
}
}
6. 자바로 윈도우프로그래밍 시스템 생성
InnerMemberEvent.java
package innerclass22;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class InnerMemberEvent extends JFrame {
JButton button1, button2, button3;
// 내부 클래스 인스턴스화]
EventHandler handler = new EventHandler();
public InnerMemberEvent() {
setTitle("내부 멤버 클래스로 이벤트 처리하기");
setLayout(new FlowLayout());
add(button1 = new JButton("1ST 버튼"));
add(button2 = new JButton("2ND 버튼"));
add(button3 = new JButton("3TH 버튼"));
addWindowListener(handler);
button1.addActionListener(handler);
button2.addActionListener(handler);
button3.addActionListener(handler);
pack();
setVisible(true);
}///////////////////
// [내부 멤버 클래스]
class EventHandler extends WindowAdapter implements ActionListener {
// 윈도우의 시스템 이벤트 처리
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);// 여기 부분 오버라이딩이 없으면 창은 꺼져도 실행은 안꺼져있음 (console빨간 네모)
}
// 버튼의 클릭 이벤트 처리
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button1)
JOptionPane.showMessageDialog(button1, "첫번째 버튼을 클릭했어요");
else if (e.getSource() == button2)
JOptionPane.showMessageDialog(button2, "두번째 버튼을 클릭했어요");
else {
JOptionPane.showMessageDialog(button3, "세번째 버튼을 클릭했어요");
}
}
}
public static void main(String[] args) {
new InnerMemberEvent();
}
}
(chat GPT로 검색)
이 코드는 Java Swing GUI 프로그래밍을 활용하여 내부 멤버 클래스로 이벤트를 처리하는 예제입니다.
우선, InnerMemberEvent 클래스는 JFrame을 상속받아서 GUI 창을 생성합니다. FlowLayout를 사용하여 컴포넌트들이 순차적으로 배치되도록 하며, 세 개의 버튼 button1, button2, button3을 생성하고 창에 추가합니다.
그리고, EventHandler 클래스를 내부 멤버 클래스로 정의합니다. 이 클래스는 WindowAdapter 클래스를 상속받아 윈도우 이벤트를 처리하고, ActionListener 인터페이스를 구현하여 버튼 클릭 이벤트를 처리합니다.
EventHandler 클래스에서 windowClosing() 메서드를 오버라이딩하여 윈도우가 닫히는 이벤트를 처리합니다. 여기서 System.exit(0)을 호출하여 프로그램을 종료합니다.
또한, actionPerformed() 메서드를 오버라이딩하여 버튼 클릭 이벤트를 처리합니다. e.getSource() 메서드를 사용하여 이벤트를 발생시킨 컴포넌트를 식별하고, JOptionPane 클래스를 사용하여 메시지 대화상자를 표시합니다.
InnerMemberEvent 클래스의 생성자에서는, 생성한 버튼과 EventHandler 클래스의 인스턴스를 등록하여 이벤트를 처리할 수 있도록 합니다. 마지막으로, setVisible(true) 메서드를 호출하여 창을 화면에 표시합니다.
main() 메서드에서는 InnerMemberEvent 클래스의 인스턴스를 생성합니다.
7. 내부 정적 클래스
내부 클래스는 static 붙이는 게 가능(정적멤버, 정적 메소드 가능)
외부클래스는 static 못씀 (정적 멤버, 정적 메소드 불가능)
외부에서 내부 접근
내부 클래스 인스턴스화(객체 생성)=> (내부 클래스 인스턴스화)객체. 접근
내부 정적 멤버: 내부클래스명.정적 멤버
JDK 16 버전부터 외부 클래스 인스턴스화 안 해도 됨
그냥 클래스명.정적멤버로 접근 가능
this키워드는 인스턴스형 멤버를 가리킬 때 사용함, 따라서 정적 메소드에서는 사용불가
언제 사용? 빌더패턴을 생성할 때
InnerStaticClass.java
package innerclass22;
/*
내부 정적 클래스:클래스안의 클래스로 class앞에 static이 붙음
- 외부 클래스의 인스턴스형 멤버는 사용할 수 없다
- 외부클래스명$내부클래스명.class로 파일이 생긴다.
※ 원래 클래스 앞에는 static을 붙일 수 없으나
내부 클래스는 가능하다
*/
class OuterStatic {
//[멤버 변수]
int outerInstanceVar;
static int sameVar;
static int outerStaticVar;
//내부 클래스 인스턴스화 하기]
InnerClass inner = new InnerClass();
// 멤버 메소드
void outerInstanceMethod() {
//[외부에서 내부로 접근하기]
//외부에서는 내부의 멤버에 접근 불가(접근하려면 반드시 내부 클래스를 인스턴스화 해야한다)
//System.out.println(innerInstanceVar);//[x]
//innerInstanceMethod();//[x]
System.out.println(inner.innerInstanceVar);//[o]
inner.innerInstanceMethod();//[o]
}///////
static void outerStaticMethod() {
//[외부에서 내부로 접근하기]
//내부의 정적 멤버[o]:내부클래스명.정적멤버
System.out.println(InnerClass.innerStaticVar);//[o]
InnerClass.innerStaticMethod();//[o]
//내부의 인스턴스형멤버[X]
//System.out.println(inner.innerInstanceVar);//[x]
}//////////
// [내부 정적 클래스]
static class InnerClass {
// [멤버 변수]
int innerInstanceVar;
static int sameVar = 1;
static int innerStaticVar;
//[생성자]
public InnerClass() {
System.out.println("내부의 클래스의 생성자");
}
//[멤버 메소드]
void innerInstanceMethod() {
//[내부에서 외부에 접근하기]
//※내부 정적 클래스에서는 외부의 인스턴스형 멤버는 사용불가(내부 멤버 클래스와 다른 점)
//System.out.println(outerInstanceVar);//[x]
System.out.println(outerStaticVar);//[o]
//outerInstanceMethod();//[x]
outerStaticMethod();//[o]
//※외부의 정적멤버 와 내부 정적 멤버 충돌할때
//※외부 멤버 정적 변수 = 내부 멤버 정적 변수
OuterStatic.sameVar=sameVar;
}
static void innerStaticMethod() {
//[내부에서 외부에 접근하기]
//외부의 정적멤버만 사용가능
//System.out.println(outerInstanceVar);//[x]
System.out.println(outerStaticVar);//[o]
//outerInstanceMethod();//[x]
outerStaticMethod();//[o]
}
}//////////
}//////////
public class InnerStaticClass {
public static void main(String[] args) {
//별도의 다른 클래스에서는 내부클래스 인스턴스화 불가능
//InnerClass inClass = new InnerClass();//[x]
//외부클래스를 인스턴스화 할 필요 없다
//내부의 인스턴스형 멤버 접근시-내부 정적 클래스 인스턴스화]
//외부 클래스명.내부클래스명 인스턴스변수 = new 외부 클래스명.내부클래스명()
OuterStatic.InnerClass inner = new OuterStatic.InnerClass();//빌더 패턴일때 주로 사용
System.out.println(inner.innerInstanceVar);
inner.innerInstanceMethod();
//내부의 정적 멤버 접근시-외부클래스명.내부클래스명.정적멤버]
System.out.println(OuterStatic.InnerClass.innerStaticVar);
}
}
외부 클래스명.내부클래스명 인스턴스 변수 = new 외부 클래스명.내부 클래스명();
은 아래 빌더 패턴일 때 사용한다.
8. 빌더 패턴
디자인 패턴 중 하나. 인자가 많은 객체 생성 시 사용하는 방법
만드는 방법
1. 멤버변수를 private
2. 내부 정적 클래스로 생성
3. 정적 내부 클래스에 똑같은 멤버변수 선언(private)
4. 내부 클래스 인자 생성자(필수 항목만 받는 생성자)
5. 멤버 변수(선택항목)를 초기화하는 세터를 생성( 외부에서 접근해야 돼서 public 붙이고 Builder타입으로 반환
6. 내부 정적 클래스타입을(Builder) 인자로 받는 생성자 정의
7. 외부 클래스 타입을 반환하는 메소드 생성
8. 필수 항목만 갖고 객체 생성
InnerStaticBuilder.java
package innerclass22;
//내부 정적 클래스: 빌더 패턴(클래스 설계시 디자인 패턴의 하나)으로 객체 생성에 사용
/*
빌더 패턴:
객체 생성과 관련된 디자인패턴
인자가 많은 객체를 생성할때 유리
*/
class Member{
//1]맴버 변수는 private으로
//필수 항목]
private String id;
private String name;
//선택 항목]
private String tel;
private String addr;
//2]내부 정적 클래스
static class Builder{
//3]외부 클래스와 똑같은 멤버변수(필드)를 갖는다.
private String id;
private String name;
private String tel;
private String addr;
//4]내부 클래스 인자생성자(필수항목만 받는 생성자)]
public Builder(String id, String name) {
this.id=id;
this.name=name;
}
//5]멤버변수(선택항목)를 초기화 하는 세터(반환타입은 void가 아니라 Builder)
// 반환는 this
public Builder setTel(String tel) {
this.tel=tel;
return this;
}
public Builder setAddr(String addr) {
this.addr=addr;
return this;
}
//7]외부 클래스 타입을 반환 하는 메소드
public Member build() {
return new Member(this);
}
}///
//6]내부 정적 클래스 타입(Builder)을 인자로 받는 생성자 정의
public Member(Builder builder) {
this.id=builder.id;
this.name=builder.name;
this.tel=builder.tel;
this.addr=builder.addr;
}
@Override
public String toString() {
return String.format("[아이디:%s,이름:%s,연락처:%s,주소:%s]",id,name,tel,addr);
}
}//////////
public class InnerStaticBuilder {
public static void main(String[] args) {
//8]필수항목만 갖고 객체 생성
Member member1=new Member.Builder("KIM" , "김길동").build();
System.out.println(member1);
Member member2 = new Member.Builder("LEE", "이길동")
.setTel("010-1234-5678")
.build();
System.out.println(member2);
Member member3 = new Member.Builder("PARK", "박길동")
.setTel("010-1234-5678")
.setAddr("가산동")
.build();
System.out.println(member3);
}/////main
}////////class
sol)
9. 익명 클래스
9-1) 메소드 안에 정의된 클래스
이런 식으로 부모의 클래스 Person을 이름을 빌려 씀 하지만 개념적으로 자식이고 이름이 없다.
그럼, 우리가 다운 캐스팅 할 때
이런 식으로 Person에서 Student로 형변환 하는데 익명클래스는 이름이 있는가?
bin객체에서도
이렇게 1, 2, 3 이렇게 인덱스 번호로 임의로 생성된다.
결국 형변환이 불가능해서 익명클래스에서 정의한 멤버에 대한 접근은 불가능하다.
결국, 오버라이딩이 목적이다.
InnerAnonymousClass.java
package innerclass22;
/*
익명 클래스]
-이름이 없는 클래스
-GUI프로그래밍 시 주로 사용(이벤트 처리하기 위해서)
-부모 클래스의 메소드를 오버라이딩하는 것이 주된 용도
-메소드 안에 정의된 클래스
-이름이 없어서 부모클래스의 생성자를 빌려서 인스턴스화 한다
-외부클래스명$1.class,외부클래스명$2.class 등..즉 클래스명이 없기때문에 만들어진 순서대로
인덱스가 부여되서
내부클래스명이 된다
형식]
부모클래스명 인스턴스변수 = new 부모클래스명(){
};//반드시 ;을 붙여라
*/
class Person{
String name;
public Person(String name) {
this.name = name;
}///////////
@Override
public String toString() {
return "이름:"+name;
}
}/////////////////////////
class Student extends Person{
String stNumber;//자식에서 새롭게 확장한 멤버변수
public Student(String name,String stNumber) {
super(name);
this.stNumber=stNumber;
}
String get() {//자식에서 새롭게 확장한 멤버 메소드]
return String.format("%s,학번:%s", super.toString(),stNumber);
}
@Override
public String toString() {
return get();
}
}////////////////////////////////
//[추상 클래스]
abstract class AbstractClass{
abstract void abstractMethod();
}/////////////////////
//[인터 페이스]
interface Inter{
void abstractMethod();
}
public class InnerAnonymousClass {
public static void main(String[] args) {
//[이름이 있는 자식클래스(Student)의 일반적인 이질화 형태]
Person person = new Student("홍길동", "2023학번");
System.out.println(person);
//[자식에서 새롭게 확장한 멤버 접근]-형변환(다운캐스팅)
Student student=(Student)person;
System.out.println(student.stNumber);
System.out.println(student.get());
Person anony = new Person("나길동") {//익명 클래스 시작
//[멤버변수]
int newVar;//익명클래스에서 새롭게 확장한 멤버
//[멤버 메소드]
void newMethod() {
System.out.println("익명 클래스에서 새롭게 확장한 메소드");
}
@Override
public String toString() {
return super.toString()+",newVar:"+this.newVar;
}
};////익명클래스 끝. {}은 Person을 상속받은 익명 클래스다
System.out.println(anony.getClass().getName());//innerclass22.InnerAnonymousClass$1
/*[자식에서 새롭게 정의한 멤버 접근]
다운캐스팅:(자식클래스명)부모타입인스턴스변수
클래스명이 없음으로 다운캐스팅 불가
고로 자식에서 새롭게 정의한 멤버 접근 불가
※고로 익명클래스는 오버라이딩이 목적*/
System.out.println(anony);
//추상 클래스를 상속받은 익명 클래스]
AbstractClass ac = new AbstractClass() {
@Override
void abstractMethod() {
System.out.println("추상메소드 오버 라이딩:추상클래스");
}
};
ac.abstractMethod();
//인터페이스를 상속받은 익명 클래스]
Inter inter = new Inter() {
@Override
public void abstractMethod() {
System.out.println("추상메소드 오버 라이딩:인터페이스");
}
};
inter.abstractMethod();//이벤트 처리할떄 주로 사용
}/////////////////main
}///////////////////class
sol)
9-2) 익명클래스로 이벤트 처리
InnerAnonymousEvent.java
package innerclass22;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class InnerAnonymousEvent extends JFrame {
JButton button1, button2, button3;
// 방법2]
private ActionListener handler = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button1)// e.getSource => e의 이벤트 발생한 객체의 주소값
JOptionPane.showMessageDialog(button1, "첫번쨰 버튼을 클릭했어요");
else if (e.getSource() == button2)
JOptionPane.showMessageDialog(button2, "두번쨰 버튼을 클릭했어요");
else {
JOptionPane.showMessageDialog(button3, "세번쨰 버튼을 클릭했어요");
}
}
};
public InnerAnonymousEvent() {
setTitle("내부 익명 클래스로 이벤트 처리하기");
setLayout(new FlowLayout());
add(button1 = new JButton("1ST 버튼"));
add(button2 = new JButton("2ND 버튼"));
add(button3 = new JButton("3TH 버튼"));
// 익명 클래스로 윈도우 종료 이벤트 처리]
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
// 익명 클래스로 버튼의 이벤트 처리]
// 방법1]
/*
* button1.addActionListener(new ActionListener() {
*
* @Override public void actionPerformed(ActionEvent e) {
* JOptionPane.showMessageDialog(button1,"첫번쨰 버튼이 클릭했어요");
*
* } }); button2.addActionListener(new ActionListener() {
*
* @Override public void actionPerformed(ActionEvent e) {
* JOptionPane.showMessageDialog(button2,"두번쨰 버튼이 클릭했어요");
*
* } }); button3.addActionListener(new ActionListener() {
*
* @Override public void actionPerformed(ActionEvent e) {
* JOptionPane.showMessageDialog(button3,"세번쨰 버튼이 클릭했어요");
*
* } });
*/
// 방법2]
button1.addActionListener(handler);
button2.addActionListener(handler);
button3.addActionListener(handler);
pack();
setVisible(true);
}///////////////////
public static void main(String[] args) {
new InnerAnonymousEvent();
}
}
sol)
'java' 카테고리의 다른 글
19일차 2023-04-03 (0) | 2023.04.03 |
---|---|
18일차 2023-03-31 (0) | 2023.03.31 |
16일차 2023-03-29 (1) | 2023.03.29 |
15일차 2023-03-28 (0) | 2023.03.28 |
14일차 2023-03-27 (0) | 2023.03.27 |