10일차 - 240109

김리오·2024년 1월 9일

학원공부 TIL

목록 보기
10/13

📌upcasting

  • 업 캐스팅, 다운 캐스팅은 서로 상속관계에 있는 타입간의 형변환만 가능하다.

  • Account 클래스

package ex09_03_upcasting;

class Account {

	String accountNo;
	String ownerName; 
	int balance;	
	
	Account(String accountNo, String ownerName, int balance) {
		this.accountNo = accountNo;
		this.ownerName = ownerName;
		this.balance = balance;
	}

	void deposit(int amount) {
		this.balance += amount;
	}

	int withdraw(int amount) throws Exception {
		if (balance < amount)
			throw new Exception("잔액이 부족합니다.");
		balance -= amount;
		return amount;
	}

}
  • CheckingAccount 클래스는 Account 클래스의 자식 클래스
package ex09_03_upcasting;

public class CheckingAccount extends Account {
	String cardNo;
	
	CheckingAccount(String accountNo, String ownerName,
					int balance, 	  String cardNo) {
		
		//파라미터 3개의 슈퍼 클래스 생성자 호출문
		//반드시 생성자의 첫번째 명령문이어야 한다.
		//예전에 this()로 생성자 호출했던 것도 연결해서 공부
		super(accountNo, ownerName, balance);
		this.cardNo = cardNo;		//클래스 안에 선언된 필드 초기화
	}

	int pay(String cardNo, int amount) throws Exception {
		if (!cardNo.equals(this.cardNo) || (balance < amount))
			throw new Exception("지불이 불가능합니다.");

		return super.withdraw(amount); //super.은 생략할 수 있다.
	}

}
  • 업캐스팅 과정에서 컴파일러에 의한 '묵시적(암시적) 형변환'이 자동으로 진행된다.
  • 업케스팅을 한 경우, 부모에서 정의된 필드나 메소드만 사용할 수 있다(참조영역축소)
public class RefTypeExample6 {
	public static void main(String[] args) {
		Account obj =
				new CheckingAccount("111-22-33333333","홍길동",10,"4444-5555-6666-7777");
		// (Account) 묵시적 형변환
		try {
			int amount = obj.pay("4444-5555-6666-7777",47000);
			System.out.println("인출액: "+amount);
			System.out.println("카드번호: "+obj.cardNo);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		
			//(1)obj.pay (2)obj.cardNo 컴파일 오류가 생기는 이유는 뭘까?
			//자바 컴파일러는 컴파일 할 때 변수의 타입만 보고
			//메소드나 필드의 존재 여부를 체크하기 때문에
			//Account 클래스에 pay, cardNo메소드가 있어야 컴파일 에러가 없다
			//but!! 컴파일 후 실행할 때는 override된 메소드를 호출한다!!!!!!!!!!!
			
		}
	}
}

📌downcasting

  • 슈퍼클래스 참조 변수 = 서브 클래스 참조 변수
public class RefTypeExample7 {
	public static void main(String[] args) {
		Account obj1 =
				new CheckingAccount("111-22-33333333","홍길동",100000,"5555-6666-7777-8888");
		
		CheckingAccount obj2 = obj1;
		//부모형을 자식형에 대입할 수 없음
		//컴파일러는 변수의 타입만 보고 대입 가능성을 검사하기 때문에 에러발생
		
		try {
			int amount = obj2.pay("5555-6666-7777-8888",47000);
			System.out.println("인출액: "+amount);
			System.out.println("카드번호: "+obj2.cardNo);
			System.out.println("잔액: "+obj2.balance);
		} catch (Exception e) {
			System.out.println(e.getMessage());
			
		}
	}
}

📌Exception 2

  • FileReader 클래스는 객체를 생성하면 FileNotFoundException을 정의하도록 설정되어 있다.
    throws로 정의하거나, try-catch로 정의하지 않으면 컴파일 오류 발생한다.
import java.io.*;

class ExceptionExample8_Filereader {
	public static void main(String[] args) {
		FileReader reader = new FileReader("some.txt");
	}
}
import java.io.FileReader;

class ExceptionExample8_Filereader_trycatch {
	public static void main(String[] args) {
		try {
			FileReader reader = new FileReader("some.txt");
			reader.close();
        //close 메소드에서도 IOException을 던지고 있으니,
		//이것에 대한 예외처리를 해줘야 한다
        
		} catch (Exception e) {
			System.out.println("파일을 찾을 수 없습니다.");
		}
		//try-catch문은 하위클래스에서 상위클래스로 작성한다.
		//상위 클래스로 정의하면 굳이 하위 클래스로 작성할 이유가 없기 때문이다. (다형성 개념과 연결됨).
		/* catch (FileNotFoundException e) {
		   System.out.println("파일을 찾을 수 없습니다.") }
		   catch (IOException e) {
		   System.out.println("입출력 오류") } 
		 */
	}
	
}
  • finally를 사용하면 try-catch문 구조에 관계없이 finally 블록 안에 있는 실행문은 반드시 작동한다.
//상속 관계에 있는 두 종류의 Exception을 처리하는 try문
//catch문 예외 순서가 부모가 자식보다 먼저오면 에러 발생
//-부모 먼저 예외를 정의하면 자식에서 예외를 정의할 필요가 없어짐 (다형성)
//FileNotFoundException -> IOException

import java.io.FileReader;
import java.io.IOException;

class ExceptionExample8_Filereader_trycatch_finally {
	

	public static void main(String[] args) {
		FileReader reader = null; // (finally) 쓰려면 main에 정의해줘야 함
		
		try {
			reader = new FileReader("some.txt");
		} 
		
		catch (Exception e) {
			System.out.println("파일을 찾을 수 없습니다.2");
		} finally { 		//IOException을 try, catch문으로 한번 더 처리해야 함
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		/* catch (FileNotFoundException e) {
		   System.out.println("파일을 찾을 수 없습니다.") }
		   catch (IOException e) {
		   System.out.println("입출력 오류") } 
		 */
	}
	
}

📌다형성(Polymorphism) 1

  • 하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것

  • Account 클래스

class Account {

	String accountNo; //계좌번호
	String ownerName; //예금주 이름
	int balance;	  //잔액
	
	Account(String accountNo, String ownerName, int balance) {//생성자
		this.accountNo = accountNo;
		this.ownerName = ownerName;
		this.balance = balance;
	}

	void deposit(int amount) {
		this.balance += amount;
	}

	int withdraw(int amount) throws Exception {
		if (balance < amount)
			throw new Exception("잔액이 부족합니다.");
		balance -= amount;
		return amount;
	}

}
  • 메소드 오버라이딩을 통해 부모 클래스에서 가지고 있던 deposit메소드의 기능이 추가되었다.
public class BonusPointAccount extends Account {
	int bonusPoint; //누적 포인트 필드
	
	BonusPointAccount(String accountNo, String ownerName,
					int balance, int bonusPoint) {
		super(accountNo, ownerName, balance);
		this.bonusPoint = bonusPoint;
	}
	
	//예금한다 기능을 다시 구현(메소드 오버라이딩)
	//상속 받은 메소드의 로직을 단순히 확장
	//super는 자식 클래스에서 부모 클래스로 상속 받은 필드와 메서드를 참조하는데 사용한다.
	void deposit(int amount) {
		balance += amount; 		//super.balance += amount;
		//super.deposit(amount);
		bonusPoint += (int)(amount * 0.001);	//실수의 값을 정수형으로 형변환casting
		//bonusPoint += amount * (1.0/1000);		//bonuspoint는 int형임.
	}

}
  • CheckingAccount / CreditLineAccount / BonusPointAccount 모두 Account 클래스의 자식들이다.
  • printAccountInfo 메소드는 파라미터로 부모 클래스 참조변수를 정의하고 있다.
    main에서 각각 정의된 obj2, obj3, obj4는 파라미터와 데이터타입이 다름에도 불구하고 컴파일 오류가 발생하거나 실행 과정에서 에러가 발생하지 않는다.
class InheritanceExample2 {
	public static void main(String[] args) {
		
		Account obj1 = new Account("111-22-333333", "임꺽정", 10000);
		printAccountInfo(obj1);

		
		CheckingAccount obj2 = new CheckingAccount("444-55-666666","홍길동",20000,"5555-6666-7777");
		printAccountInfo(obj2);

		
		CreditLineAccount obj3 = new CreditLineAccount("777-88-999999","김선달",30000,2000000);
		printAccountInfo(obj3);

		// 다양한 타입의 객체를 가지고 있는 메소드를 호출한다.
		BonusPointAccount obj4 = new BonusPointAccount("000-00-000000", "김미영",0,0);
		printAccountInfo(obj4);

		
	}
	
	//static을 안 붙이면, printAccountInfo가 포함된 클래스를 인스턴스화 한 후에야 이 메소드를 사용할 수 있게 됨
	//다양한 타입의 인스턴스 참조변수를 부모 클래스 하나의 파라미터로 받을 수 있다. (부모는 자식을 다 감싼다)
	static void printAccountInfo (Account obj) {
		System.out.println("계좌번호:"+obj.accountNo);
		System.out.println("예금주 이름:"+obj.ownerName);
		System.out.println("잔액:"+obj.balance);
		System.out.println();
	}

}

📌다형성(Polymorphism) 2

  • MessageSender abstract 클래스 : abstract 메소드를 포함하고 있다.
public abstract class MessageSender {
	String title;
	String senderName;

	MessageSender (String title, String senderName) {
		this.title = title;
		this.senderName = senderName;
	}
	
	abstract void sendMessage(String recipient);

}
  • SMSSender 클래스 : MessageSender 클래스를 상속 받으면서 sendMessage 메소드를 구현하고 있다.
class SMSSender extends MessageSender {
	
	String returnPhoneNo;
	String message;

	SMSSender(String title, String senderName,
			String returnPhoneNo,String message) {
		super(title, senderName);
		this.returnPhoneNo = returnPhoneNo;
		this.message = message;
	}
	
	// 슈퍼 클래스의 메서드를 오버라이드하는 메서드
	// 추상 클래스를 상속받은 클래스는 추상 메서드를 구현(implement)해야만 한다!!! (override)
	
	void sendMessage(String recipient) {
	    System.out.println("------------------------------");
	    System.out.println("제목: " + title);
	    System.out.println("보내는 사람: " + senderName);
	    System.out.println("전화번호: " + recipient);
	    System.out.println("회신 전화번호: " + returnPhoneNo);
	    System.out.println("메시지 내용: " + message);
	}

}
  • EmailSender 클래스 : MessageSender 클래스를 상속 받으면서 sendMessage 메소드를 구현하고 있다.
class EMailSender extends MessageSender {
	
	String senderAddr;
	String emailBody;

	EMailSender(String title, String senderName,
			String senderAddr, String emailBody) {
		super(title, senderName);
		this.senderAddr = senderAddr;
		this.emailBody = emailBody;
	}
	
	// 슈퍼 클래스의 메서드를 오버라이드하는 메서드
	// 추상 클래스를 상속받은 class는
	// 추상 메서드를 구현(implement)해야만 한다!!! (override)
	
	void sendMessage(String recipient) {
		  System.out.println("------------------------------");
		  System.out.println("제목: " + title);
		  System.out.println("보내는 사람: " + senderName + "\n" 
			                 + "보낸 주소 : " + senderAddr);
		  System.out.println("받는 사람: " + recipient);
		  System.out.println("내용: " + emailBody);
	}

}
  • main에서 슈퍼 클래스 타입의 변수를 파라미터로, 서브 클래스 참조변수를 인자로 send메소드를 정의하고 있다. 슈퍼 클래스 타입 변수 하나로 서브 클래스 참조변수를 모두 인자로 받을 수 있다.
public class InheritanceExample8 {
	public static void main(String[] args) {
		EMailSender obj1 = new EMailSender("생일을 축하합니다", "고객센터",
											"admin@dukeeshop.co.kr", 
											"10% 할인쿠폰이 발행되었습니다.");
		SMSSender obj2 = new SMSSender("생일을 축하합니다", "고객센터",
									   "02-000-0000", "10% 할인쿠폰이 발행되었습니다.");
		
		//서브 클래스 참조변수 obj1, obj2를 가지고 메소드를 호출
		send(obj1, "hatman@yeyeye.com");
		send(obj1, "stickman@hahaha.com");
		send(obj2, "010-000-0000");

	}
	/*
	 	1.MessageSender obj : 슈퍼 클래스 타입의 파라미터
	 	
	 	2.MessageSender 클래스에서 sendMessage 메소드를 주석 처리할 경우 에러가 발생한다.
	 	
	 	3.자바 컴파일러는 컴파일 과정에서 해당 클래스에 그 메소드가 있는지 없는지 체크한다.
	 	  주석처리를 하면 MessageSender 클래스에 sendMessage()메소드가 존재하지 않아서
	 	  The method sendMessage(String) is undefined for the type
	 	  에러가 발생한다.
	 	  
	 	4.JVM은 객체의 메소드를 호출할 때 변수 타입에 상관없이 객체가 속하는 클래스의 메소드를 호출한다.
	 */
	
	
	
	//MessageSender obj : 슈퍼 클래스 타입의 파라미터
	static void send(MessageSender obj, String recipient) {
		//어느 클래스의 sendMessage메소드가 호출될까?
		//EmailSendr(obj1) 또는 SMSSender(obj2)에, 즉 객체에 정의된 overriding된 메서드를 호출한다 (동적바인딩)
 - 동적바인딩 개념과 연결됨
		obj.sendMessage(recipient);
	}

}

📌인터페이스(interface)

  • 추상클래스보다 추상화 정도가 높다. (실제 구현된 것이 전혀 없는 기본 설계도)

  • 추상메서드와 상수만을 멤버로 가질 수 있다.

  • 인스턴스를 생성할 수 없다.

  • 다중 상속을 지원하지 않지만, 다중상속효과를 간접적으로 얻을 수 있다.

  • Lendable 인터페이스

public interface Lendable {

	//대출한다.
	public abstract void checkOut(String borrower, String date);

	//반납한다.
	public abstract void checkIn();

}
  • SeparataeVolume 클래스
//대출 가능 인터페이스를 구현하는 단행본 클래스
//SeparateVolume 클래스는 Lendable 인터페이스를 '구현한다' 라고 한다.

public class SeparateVolume implements Lendable {

	String requestNo;
	String bookTitle;
	String writer;
	String borrower;
	String checkOutDate;
	byte state;

	//필드에 선언된 값을 변수를 통해 들어온 값으로 변경 하도록
	SeparateVolume(String requestNo, String bookTitle, String writer) {
		this.requestNo = requestNo;
		this.bookTitle = bookTitle;
		this.writer = writer;
	}
	//인터페이스에서 abstract 메소드를 구현하는 클래스에서는 메소드를 public으로 해야 함
	 public void checkOut(String borrower, String date) {
		if (state != 0)
			return;
		this.borrower = borrower;
		this.checkOutDate = date;
		this.state = 1;	// 필드의 state를 바꿔야 함
		System.out.println("*" + bookTitle + " 이(가) 대출되었습니다.");
		System.out.println("저  자 :"+writer); //추가된 부분
		System.out.println("대출인:" + borrower);
		System.out.println("대출일:" + date + "\n");

	}

	public void checkIn() {
		borrower = null;
		checkOutDate = null;
		state = 0;
		System.out.println("*" + bookTitle + " 이(가) 반납되었습니다.\n");

	}

}
  • main : 인터페이스 타입의 배열 arr[ ]을 정의하고 있다.
    checkOutAll 메소드를 정의하여 주석처리된 결과값을 출력하려고 한다.
  • checkOut 메소드는 SeparateVolume 클래스로부터 참조하고 있고,
    배열에 저장된 각 인스턴스별로 checkOutAll 메소드를 실행한 결과값을 얻으려고 한다.
  • ⭐향상된 for문을 이용하는 논리를 이해하려면, 참조형 배열이 어떤 구조로 메모리에 저장되어 있는지 그림으로 이해하고 있어야 한다. (2차원 배열이 저장되어 있는 논리와 유사함)
/* 출력된 결과
*푸코의 진자 이(가) 대출되었습니다.
저  자 :에코
대출인:홍길동
대출일:2024-01-09

*서양미술사 이(가) 대출되었습니다.
저  자 :곰브리치
대출인:홍길동
대출일:2024-01-09

*마이크로서비스를 위한 자바 프로그래밍 이(가) 대출되었습니다.
저  자 :유시진
대출인:홍길동
대출일:2024-01-09
*/

public class InterfaceExample {
	public static void main(String[] args) {
		// int[] a = new int[3];
		// String[] a = new String[3];
		Lendable arr[] = new Lendable[3]; // 인터페이스 타입의 배열

		// 배열에 SeparateVolume 타입의 여러 객체 주소 저장
		arr[0] = new SeparateVolume("883ㅇ", "푸코의 진자", "에코");
		arr[1] = new SeparateVolume("609.2", "서양미술사", "곰브리치");
        arr[2] = new SeparateVolume("457.9", "마이크로서비스를 위한 자바 프로그래밍", "유시진");


		checkOutAll(arr, "홍길동", "2024-01-09");
	}

	static void checkOutAll(Lendable[] arr, String borrower, String date) {
		
		for(Lendable a : arr) { 
			a.checkOut(borrower, date); 
		}
		
		}
		
	}



📌240109 과제

  • 문제
1. 인터페이스 Movable
2. 추상 메서드
     // 절대 위치로 이동한다 
	void moveTo(int x, int y);  
    
    // 상대 위치만큼 이동한다.
	void moveBy(int xOffset, int yOffset); 
==============================================================
1. interface 이름 : Transformable(부모 Movable)
2. 추상 메서드
    // 크기를 변경한다
    void resize(int width, int height);   
==========================================================
1. 클래스 이름 : Rectangle(부모 : Transformable)
2. 생성자 : 필드 초기화(int x, int y, int width, int height)
3. 필드 : 
    int x, y, width, height;
4. 메서드 - 오버라이딩
    resize(int width, int height) 
        기능) 두 개의 매개변수를 이용해 필드 초기화  
    
5. 메서드 -오버라이딩
   moveTo(int x, int y)
     기능) 두 개의 매개변수를 이용해 필드 초기화  
     
6. 메서드 -오버라이딩
   moveBy(int xOffset, int yOffset)
     기능) 기존 x값에 xOffset을 더해 x를 구한다.
          기존 y값에 yOffset을 더해 y를 구한다.
======================================
다음 조건을 만족하는 printRectangle()메서드 완성하세요.
public static void main(String args[]) {
        Rectangle obj = new Rectangle(100, 200, 10, 10); 
        printRectangle(obj);
        
        obj.moveTo(25, 35);            
        printRectangle(obj);
        
        obj.moveBy(-5, -5);           
        printRectangle(obj);
        
        obj.resize(30, 30);           
        printRectangle(obj);
    }
    
출력결과)    
사각형: 위치(100, 200) 크기( 10 x  10) 
사각형: 위치( 25,  35) 크기( 10 x  10) 
사각형: 위치( 20,  30) 크기( 10 x  10) 
사각형: 위치( 20,  30) 크기( 30 x  30) 
    
  • Movable 인터페이스
public interface Movable {
	abstract void moveTo(int x, int y);

	abstract void moveBy(int xOffset, int yOffset);

}
  • Transformable 인터페이스
public interface Transformable extends Movable {
	
	abstract void resize(int width, int height);

}
  • Ractangle 클래스
public class Rectangle implements Transformable {

	int x, y, width, height;

	Rectangle(int x, int y, int width, int height) {
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}

	public void moveTo(int x, int y) {
		this.x = x;
		this.y = y;

	}

	public void moveBy(int xOffset, int yOffset) {
		this.x += xOffset;
		this.y += yOffset;

	}

	public void resize(int width, int height) {
		this.width = width;
		this.height = height;
	}

}
  • 실행문
public class Rectangle_Main {

	public static void main(String args[]) {
		Rectangle obj = new Rectangle(100, 200, 10, 10);
		printRectangle(obj);

		obj.moveTo(25, 35);
		printRectangle(obj);

		obj.moveBy(-5, -5);
		printRectangle(obj);

		obj.resize(30, 30);
		printRectangle(obj);
	}

	static void printRectangle(Rectangle obj) {
		System.out.println("사각형: 위치(" + obj.x + ", " + obj.y + ") 크기(" + obj.width + " x " + obj.height + ")");

	}

}
profile
생각하는 사람이 되고 싶다

0개의 댓글