본문 바로가기

JAVA

제네릭을 활용한 Double타입 계산이 가능한 계산기 만들기

여러 자료를 보며 내가 이해한 제네릭이란 메서드나 클래스의 타입에 대한 지정을 최초 생성시에 하는 것이 아닌 인스턴스를 만들 때 외부에서 지정해주는 것이었다.

 

한마디로 핵심은 외부에서 타입을 지정해 준다는 것!

 

1. 첫번째 시도

  • 계산의 결과를 담는 results 배열의 타입을 제네릭으로 지정해주고, 계산을 수행하는 calculate 메서드의 리턴타입과 매개변수 타입을 동일한 제네릭으로 선언
  • Operator ‘+’ cannot be applied to ‘T’, ‘T’ 에러 발생
public class A<T> {
    private ArrayList<T> results = new ArrayList<>();

    public T calculate(T number1, T number2){

        results.add(number1);
        return number1 + number2;
    }

}

 

gpt 에게 물어본 결과, 제네릭인 T타입이 어떤 데이터 타입이 올 수 있을지 모르기 때문에 '+'연산 자체를 지원하는지 여부도 알 수 없기 때문에 에러가 났다고 알려줬다 -> 결론적으로 "타입의 제한이 필요하다"는 결론이 나왔다

 

2. 두번째 시도

제네릭의 타입 제한 : <K extends T>   - K는 T이거나 T를 상속받은 하위타입이어야 함

  • 피연산자의 타입을 Number의 하위 타입만 받을 수 있게 가능하도록 제한함
  • 동일한 에러 발생
public class A<T extends Number> {
    private ArrayList<T> results = new ArrayList<>();

    public T calculate(T number1, T number2){

        results.add(number1 + number2);
        return  result;
    }

}

    

 

타입의 제한을 걸어주었지만, Integer가 들어오는 경우와 Double이 들어오는 경우에 따라서 더하기 연산을 수행하면 결과타입이 double이 될지 int가 될지 자바 컴파일러는 모르기 때문에 에러가 난 것 같다

 

이 부분에서 시간이 꽤 들었는데 그 이유는 아래의 예시는 잘 작동이 됐었기에 당연히 각각의 타입을 알아서 구분하고 더하기까지 해줄 수 있을 거라고 생각해서 그랬던 것 같다🙄

 

3. 세번째 시도

메서드 수준에서의 제네릭 : public <T> Double calculate(T number1, T number2), return 타입 앞에 <T> 붙이기

  • calculate 메서드의 return 타입을 Double로 지정해 주고, results 의 타입 또한 Double로 지정
    • 값이 정수로 들어오든, 부동소수점형으로 들어오든지 간에 정확한 계산 결과값을 보여주기 위해서는 Double로 고정하는 게 좋다고 생각했기 때문이다!
public class A {
    private ArrayList<Double> results = new ArrayList<>();

    public <T extends Number> Double calculate(T number1, T number2){
        Double result = number1.doubleValue() + number2.doubleValue();
        results.add(result);
        return  result;
    }
}

 

완성! 이제 이 코드를 바탕으로 과제에 반영해보았다

 

4. 완성

피연산자에 정수를 넣어도 실수를 넣어도 결과가 정확하게 나왔다!

public class ArithmeticCalculator {

    private OperatorType addOperator = OperatorType.ADD;
    private OperatorType subtractOperator = OperatorType.SUBTRACT;
    private OperatorType divideOperator = OperatorType.DIVIDE;
    private OperatorType multiplyOperator = OperatorType.MULTIPLY;

    private ArrayList<Double> results = new ArrayList<>();

    public <T extends Number> Double calculate(T number1, T number2, char operator){
        double answer = 0.0;

        //연산 수행
        if (operator == addOperator.getOperator()) {
            answer = number1.doubleValue() + number2.doubleValue();
        } else if (operator == subtractOperator.getOperator()) {
            answer = number1.doubleValue() - number2.doubleValue();
        } else if (operator == multiplyOperator.getOperator()) {
            answer = number1.doubleValue() * number2.doubleValue();
        } else if (operator == divideOperator.getOperator()) {
            answer = number1.doubleValue() / number2.doubleValue();
        }

        results.add(answer);
        return answer;
    }

    public String getAllResults(){
        return results.toString();
    }

    public Double getResults(int index){
        return results.get(index);
    }

    public void setResult(int index, double value){
        results.set(index, value);
    }

    public void deleteFirstResult(){
        results.remove(0);
    }

}

 

 

추가적으로 안 것

추가적으로 이번 과제를 하면서 git에 시간을 엄청 많이 쓴 것 같다 ㅎㅎ...

 

잘못 올린 커밋 메시지를 수정하고 싶어서 vim에서 esc후 :wq를 아무리 눌러봐도 아무런 동작도 일어나지 않았다 ㅠㅠ

거의 몇시간동안 시도해보고... 심지어 친구 노트북으로도 똑같이 수행해봤는데 너무 잘 되서 계속 스트레스를 받던 도중에 나의 경우는 vim이 아니라 Nano가 기본 편집기로 설정되어 있다는 것을 깨닫고 해결했다,,,

 

Push 후 Commit 수정

https://kyn1013.tistory.com/167

 

그 다음으로는 실수로 이상하게 연속적으로 커밋한 기록을 발견하고 push가 끝난 후의 커밋을 삭제하는 방법도 알게 됐다

Push 후 Commit 삭제

https://kyn1013.tistory.com/175