'4월 29일' 열한 번째 기록 [TIL]

가은·2024년 4월 29일
0

I Learned [본 캠프]

목록 보기
15/135
post-thumbnail

👩‍🏫 오늘의 출석

❓열한 번째, 9 to 9을 해 본 소감❓

시간이 참 빨리 가서 다행이다. 안 갈 줄 알았던 시간인데 알차게 잘 보내고 있는 것 같아서 조금 마음이 놓인다. 94일 중 오늘로 11일째! 벌써 10%가 넘게 출석했다는 이야기다! 팀원들과 이런 이야기 하며 오늘도 참 하루가 빠르게 흘러갔다고 얘기했다. 그리고 확실히 Level 2과제를 풀어보니 1과 달리 아직 자유자재로 코드를 다루고, 빠르고 효율적으로 코드를 작성하지는 못하는 점이 아쉬웠다. 아직 배울 것도 많고, 열심히 노력해야 할 부분들도 참 많이 남은 것 같다. 그래도 하기 싫다거나, 재미없다는 생각은 자바 공부를 하면서 한 번도 안 들었다는 점이 참 신기하다. 이래서 사람이 하고 싶은 걸 해야 한다는 걸까? 아직 내 길이, 적성이 맞는지 확신은 없어 불안하다가도 주말에도 하루 종일 시간 내서 더 공부해야겠다 생각하고 열심히 강의를 듣는 내 모습에 지금의 선택과 시간을 후에 후회하지는 않겠다는 생각이 들었다.

📑오늘 학습한 내용

오늘부터는 오전 9시부터 10시까지 한 시간동안 알고리즘을 푸는 시간을 가진다.
아래는 오늘 날짜에 풀어야했던 알고리즘 문제이다.

🧩오늘의 알고리즘 : 각도기🧩

/*java*/
class Solution {
    public int solution(int angle) {
        int answer = 0;
        
       if (0 < angle && angle < 90){
           answer = 1;
       } else if (angle == 90){
           answer = 2;
       } else if (90 < angle && angle < 180) {
           answer = 3;
       } else if(angle == 180){
           answer = 4;
       } return answer;
    }
}
#python
def solution(angle):
    if 0 < angle < 90:
        return 1  # Acute angle
    elif angle == 90:
        return 2  # Right angle
    elif 90 < angle < 180:
        return 3  # Obtuse angle
    elif angle == 180:
        return 4  # Straight angle
    else:
        return "Invalid angle"

이후에는 짧게 과제와 주차 관련 발제를 들은 후 개인과제 Level2를 풀었다.

❣️개인과제

✔️첫 번째 요구사항

  • 양의 정수 2개(0 포함)와 연산 기호를 매개변수로 받아 사칙연산(+,-,*,/) 기능을 수행한 후 결과 값을 반환하는 메서드와 연산 결과를 저장하는 컬렉션 타입 필드를 가진 Calculator 클래스를 생성합니다.
    • 나눗셈에서 분모에 0이 들어오거나 연산자 기호가 잘 못 들어온 경우 적합한 Exception 클래스를 생성하여 throw 합니다. (매개변수로 해당 오류 내용을 전달합니다.)
    // 0으로 나누기나 잘못된 연산자 기호에 대한 예외 클래스
class CalculatorException extends Exception {
    public CalculatorException(String message) {
        super(message);
    }
}

public class Calculator {
    // 연산 결과를 저장하는 컬렉션 타입 필드
    private List<Double> results = new ArrayList<>();

    // 산술 연산을 수행하고 결과 값을 반환하는 메서드
    public double calculate(double num1, double num2, char operator) throws CalculatorException {
        double result;

        // 연산자 기호에 따라 산술 연산 수행
        switch (operator) {
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num1 - num2;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                // 0으로 나누기 확인
                if (num2 == 0) {
                    throw new CalculatorException("0으로 나눌 수 없습니다.");
                }
                result = num1 / num2;
                break;
            default:
                // 잘못된 연산자 기호에 대한 예외 처리
                throw new CalculatorException("잘못된 연산자 기호입니다.");
        }
        // 연산 결과를 컬렉션 필드에 저장
        results.add(result);
        return result;
    }

    // 연산 결과 컬렉션을 반환하는 게터 메서드
    public List<Double> getResults() {
        return results;
    }
}

✔️두 번째 요구사항

  • Level 1에서 구현한 App 클래스의 main 메서드에 Calculator 클래스가 활용될 수 있도록 수정합니다.
    • 연산 수행 역할은 Calculator 클래스가 담당합니다.
      • 연산 결과는 Calculator 클래스의 연산 결과를 저장하는 필드에 저장됩니다.
    • 소스 코드 수정 후에도 수정 전의 기능들이 반드시 똑같이 동작해야합니다.
  public class App {
    public static void main(String[] args) {
        /* Calculator 인스턴스 생성 */
        Calculator calculator = new Calculator();

        Scanner sc = new Scanner(System.in);

        /* 루프 시작 */
        while (true) {
            System.out.println("첫 번째 숫자를 입력하세요: ");
            double firstNum = sc.nextDouble(); // 보다 정확한 계산을 위해 int 대신 double 사용
            System.out.println("두 번째 숫자를 입력하세요: ");
            double secondNum = sc.nextDouble();

            System.out.print("사칙 연산 기호를 입력하세요 (+, -, *, /): ");
            char operator = sc.next().charAt(0);

            try {
                // Calculator 클래스를 사용하여 계산 수행
                double result = calculator.calculate(firstNum, secondNum, operator);
                System.out.println("결과: " + result);
            } catch (CalculatorException e) {
                // 계산 중 발생할 수 있는 CalculatorException 처리
                System.out.println("오류: " + e.getMessage());
            }

            // 스캐너 버퍼 비우기
            sc.nextLine();

            System.out.println("더 계산하시겠습니까? (종료하려면 'exit'을 입력하세요)");
            String text = sc.nextLine();
            if (text.equals("exit")) {
                break;
            }
        } /* 루프 종료 */
        sc.close(); // 사용이 끝난 스캐너 닫기
    }
}

✔️세 번째 요구사항

  • App 클래스의 main 메서드에서 Calculator 클래스의 연산 결과를 저장하고 있는 컬렉션 필드에 직접 접근하지 못하도록 수정합니다. (캡슐화)
    • 간접 접근을 통해 필드에 접근하여 가져올 수 있도록 구현합니다. (Getter 메서드)
    • 간접 접근을 통해 필드에 접근하여 수정할 수 있도록 구현합니다. (Setter 메서드)
    • 위 요구사항을 모두 구현 했다면 App 클래스의 main 메서드에서 위에서 구현한 메서드를 활용 해봅니다.
public class Calculator {
    /* 연산 결과를 저장하는 컬렉션 타입 필드를 외부에서 직접 접근 하지 못하도록 수정*/
    private List<Double> results = new ArrayList<>();

    // 산술 연산을 수행하고 결과 값을 반환하는 메서드
    ...
     // 연산 결과 컬렉션을 간접적으로 가져오는 Getter 메서드
    public List<Double> getResults() {
        return new ArrayList<>(results); // 직접적인 수정을 방지하기 위해 결과의 복사본을 반환
    }

    // 연산 결과 컬렉션을 간접적으로 수정하는 Setter 메서드
    public void setResults(List<Double> newResults) {
        results = new ArrayList<>(newResults); // 직접적인 수정을 방지하기 위해 새로운 리스트로 결과를 대체
    }
}
    

✔️네 번째 요구사항

  • Calculator 클래스에 저장된 연산 결과들 중 가장 먼저 저장된 데이터를 삭제하는 기능을 가진 메서드를 구현한 후 App 클래스의 main 메서드에 삭제 메서드가 활용될 수 있도록 수정합니다.
/*App class*/
  System.out.println("첫 번째 저장된 데이터를 삭제하시겠습니까? (삭제하려면 'yes'를 입력하세요)");
            String deleteOption = sc.nextLine();
            if (deleteOption.equals("yes")) {
                // 연산 결과 중 첫 번째 저장된 데이터 삭제 전에 저장된 결과 출력
                System.out.println("삭제 전 저장된 값: " + calculator.getResults());

                // 연산 결과 중 첫 번째 저장된 데이터 삭제
                calculator.deleteFirstResult();
                System.out.println("첫 번째 저장된 데이터가 삭제되었습니다.");

                // 연산 결과 중 첫 번째 저장된 데이터 삭제 후의 결과 출력
                System.out.println("삭제 후 저장된 값: " + calculator.getResults());
            }
/*Calculator class*/
    // 연산 결과 리스트에서 첫 번째 데이터를 삭제하는 메서드
    public void deleteFirstResult() {
        if (!results.isEmpty()) {
            results.remove(0);
        }
    }

✔️다섯 번째 요구사항

  • Calculator 클래스에 저장된 연산 결과들을 조회하는 기능을 가진 메서드를 구현한 후 App 클래스의 main 메서드에 조회 메서드가 활용될 수 있도록 수정합니다.
/*App class*/
            System.out.println("저장된 결과를 조회하시겠습니까? (삭제하려면 'yes'를 입력하세요)");
            String inquiryOption = sc.nextLine();
            if (inquiryOption.equals("yes")) {
                // 조회된 결과 출력
                List<Double> results = calculator.inquiryResults();
                System.out.println("저장된 결과: " + results);
            }
/*Calculator class*/
    // 연산 결과 리스트를 조회하는 메서드
    public List<Double> inquiryResults() {
        return new ArrayList<>(results);
    }

Level 2의 요구사항 7까지 풀고서 자바 5주차 나머지 강의를 들고 나머지 시간에는 자바의 정석 유튜브 강의를 들었다.

💻자바의 정석 내용정리

참조변수의 형변환

  • 사용할 수 있는 멤버의 갯수를 조절하는 것
  • 조상 자손 관계의 참조변수는 서로 형변환 가능
class Car {
	Strigng color;
    int door;
    
    void dirve() {
    	System.out.println("dieve~");
    }
    void stop() {
    	System.out.println("stop!");
    }
}
class FireEngine ectends Car {
	voig water() {
    	System.out.println("water!!");
    }
}
FireEngine f = new FireEngine();
Car c = (Car)f;							// 조상인 Car타입으로 형변환 가능
FireEnigne f2 = (FireEnigne)c;			// 자손인 FirweEinge타입으로 형변환 가능
Ambulance a = (Ambulance)f;				// 에러, 상속관계가 아닌 클래스 간의 형변환 불가능

EX 1-1)

public static void main(Strign args[]) {
	Car car = null;
    FireEngine fe = new FireEngine();
     FireEngine fe2 = null;
     
     fe.water();
     car = fe;			// Car = (Car)fe;에서 형변환이 생략됨
     car.water();  		// 컴파일에러, Car타입의 참조변수로는 water() 호출 불가
     fe2 = (FireEngine)Car;		// 조상타입 → 자손타입 형변환
     fe2.water();
     Car car2 = (Car)fe2;		// 자손타입 → 조상타입 형변환

}

FireEngine의 멤버 개수는 5개(color, door, drive, stop, water)
Car의 멤버 개수는 4개(color, door, drive, stop)
⇒ Car 타입으로 형변환을 한 fe는 water() 호출이 불가능 함.

EX 1-2)

public static void main(Strign args[]) {
	Car c = new Car();
    FireEngine fe = (FireEngine)c;		// 형변환 실행시 에러
    fe.water();							// 컴파일 오류 없음
    }

위와 같이 컴파일 에러는 없지만 형변환 실행시 에러가 발생할 수 있기 때문에 참조변수 현변환은 실제 객체가 무엇인지가 중요함!

instanceof 연산자

  • 참조변수의 형변환 가능 여부를 확인하기 위해 사용
    - 가능하면 true 반환
  • 형변환 전에 반드시 instanceod로 확인해야 함
void dowork(Car c) { // Car 또는 Car의 모든 자손 가능
// dowork(new Car());, dowork(new FireEngine());, dowork(new Ambulance()); 3문자 모두 가능
//dowork(new FireEngine());은 Car c = new FireEngine(); dowork(c);와 같음
	if(c instanceof FireEngine) {			// 1. 형변환이 가능한지 확인
    	FireEnigne fe = (FireEngine)c;		// 2. 형변환
        fe.water();
        ...
    }
}
FireEngine fe = new FireEngine();
System.out.println(fe instanceof Object);			//true
System.out.println(fe instanceof Car);				//true
System.out.println(fe instanceof FireEngine);		//true

	Object obj = (Object)fe;		// 가능
    Car c = (Car)fe;				// 가능

Q. 참조변수의 형변환을 하는 이유는?
A. 참조변수를 변경함으로써 사용할 수 있는 멤버의 갯수를 조절하기 위해

Q. instanceof연산자는 언제 사용?
A. 참조변수를 형변환하기 전에 형변환 가능여부를 확인할 때

매개변수의 다형성

  • 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있음

    다형성

    1. Tv t = new SmartTv(); [조상 타입 참조 변수로 자손 타입 객체를 다루는 것]
    2. 참조변수의 형변환 [사용 가능한 멤버 갯수 조절]
    3. instanceod 연산자 [형변환 가능 여부 확인]

다형성의 장점
1. 다형적 매개변수
2. 하나의 배열로 여러 종류 객체 다루기

class Product {
	int price;
    int bonusPoint;
}

class Tv extends Product ()
class Computer extends Product ()
class Audio extends Product ()

class Buyer {
	int money = 1000;
    int bonusPoint = 0;
}

하지만 다형성을 이용하여 작성한다면? 오버로딩이 필요 없음.

추가
아래의 코드는 위쪽에 있는 코드 두 줄을 합쳐 아래의 한 줄 코드로 작성할 수 있다는 것을 보여주는 예시 코드

0개의 댓글