안녕하세요. 이번 시간에는 Java의 switch 문에 대해 알아보겠습니다. c언어의 switch문하고 다를 것은 없고요. 이번에 제가 낸 문제에서, 쓰면 좋겠다 싶어서 소개를 해 보려고 해요. 이 글에서는 string switch문이 어떻게 돌아가는지를 먼저 소개하고, 어떻게 적용할 수 있는지 알아보겠습니다. string 빼고 나머지는 제가 예전에 c언어 시간에 소개했던 switch문과 동일하므로, 관련 글의 연장선 정도라고 보시면 좋겠습니다.

 

[관련글]

c언어 switch문에 대해 알아봅시다.

 


 java에서는 String도 switch문이 됩니다. 저만 몰랐을 수도 있겠지만요. 이 프로그램은, 간단합니다. acquire를 입력받으면, 뎁스를 하나 증가시키고 acquire!를 출력합니다. release를 입력받으면 뎁스를 하나 감소시키고 release!를 출력해요. next를 입력받으면 그냥 break를 걸어버립니다.

 

 

 acquire를 입력한 순간에, 어떤 일이 일어나는지 보겠습니다.

 

 

 먼저 hashCode를 호출합니다.

 

 최종 결과가 -1164222250이 나오는 듯 하네요. 사실, 이 메서드를 절찬리에 이용하는 자료구조가 있는데요. hash 가 붙은 것들이 이 메서드를 이용합니다.

 

 이것은 어떤 버킷에 있는지를 hashCode 값을 토대로 알아내기 때문이에요. "ab"가 있는지 판단하기 위해서, hashCode와 보조 해시를 통해서 어느 버킷에 있어야 하는지를 알아냅니다. 그것이 0번 버킷이라 합시다.

 

 그러면 0번 버킷에 있는 것들을 모두 순회해서 "ab"가 있으면 "ab"가 있다고 판단하는 식입니다. 내부적으로 string switch 문에서, 해쉬 계열을 쓰는지, 그렇지 않은지는 잘 모르겠습니다. 사실, hashCode는 해시 맵에 넣기 위해서도 있지만, String을 int나 long으로 압축하기 위해서 사용하기도 하기 때문입니다.

 

 제가 예전에 쓴 을 보면, String을 int나 long으로 압축해서 어떻게 문제를 푸는지 잘 나와 있습니다. 아마도, hashCode로 스트링을 int나 long으로 떨군 다음에, case 처리를 하기 위해서 그렇게 하지 않았나. 정도로만 추정합니다.

 


  이제 다시 돌아와 보겠습니다. 문자열 A와 B가 같다면 hashCode가 같습니다. hashCode가 다르다면, 문자열 A와 B는 같지 않습니다. 이 부분은, 당연하게도, 이 문서에 아주 잘 나와 있습니다. must가 왜 붙었는지도 곰곰히 생각해 보시면 좋겠네요. 어찌 되었던, 해시 값이 같다면 비교하는 문자열 둘은 같을 확률이 1%라도 있는 것입니다.

 

 그러므로 equals로 비교하게 됩니다. 여기서 같다고 판정이 되면 어떻게 될까요?

 

 

 case문 안으로 들어가서 case문 안에 있는 것을 수행하게 됩니다. 이 부분을 디컴파일러로 보도록 하겠습니다.

 

 

 먼저 hashCode로 정수로 떨궈버린 다음에 case문으로 들어감을 알 수 있어요.

 

 다음에 var5 값을 가지고, 실제 로직을 수행함을 알 수 있어요. 여기에서는 String을 int나 long으로 바꾼 다음에, equals 조건을 통해서, 실제로 case문이 걸린 String이 맞는지 확인하고, 맞으면 해당 문장을 수행한다. 정도로만 정리하면 좋겠네요.

 


 이제, 이 문제의 상황을 정리해 봅시다. 보시면, op가 next인 경우에는 카드를 버리고, release인 경우에도 조건을 잘 해석해 보면, 리소스를 반납하고 카드를 버림을 알 수 있어요. acquire인 경우는 조금 다른데요. 현재 누군가 리소스를 가지고 있는지 확인한 후에, 그렇지 않으면, 리소스를 점유하고, 카드를 버림을 알 수 있어요.

 

 이를, 코드로 표현하면 아래와 같아요. 먼저, release와 next인 경우만 정리해 봅시다.

 

 

 release인 경우에는 노란색, 군청색 순서로 수행됩니다. 그런데, next인 경우에는 군청색만 수행됩니다. 어? 그러면, release일 때, 노란색 부분을 수행하고 자연스럽게 군청색 부분을 내려오게끔 fall through를 이용해도 좋겠네요.

 

 

 이렇게 구현하시면 되겠네요. 다음에 acquire 부분은 Resource가 누군가에 의해 점유되고 있는지 확인한 후에, 그렇지 않으면 리소스를 점유하고, 카드를 버리는 로직이 들어가야 하는데요. 이 부분은 case "acquire": 절에 적용하면 됩니다.

 

 

 이를 모두 적용한 doTurn 메소드는 위와 같습니다. 조심해야 할 점은 case "acquire": 절의 맨 끝에 break;를 걸었다는 점입니다. 이는, break문을 걸지 않으면, if문에 걸릴 때 discardCard를 2번 할 수 있고, 그렇지 않으면 카드를 들고 있어야 함에도, 카드를 버리기 때문입니다. 전체 풀 소스 코드는 링크에 있습니다.