반응형

 java에서, String을 Integer, 혹은 int형으로 변환하기 위해서 각각 valueOf라던지, parseInt를 많이 사용하는 편입니다. 이들은 내부적으로 어떻게 동작할까요? parseInt를 먼저 봅시다.

 

 

 615번째 줄에서 같은 이름의 메서드를 호출합니다. 그런데, 2번째 인자가 10인데, 이는 10진법인 s를 int형으로 바꾸겠다는 것을 나타냅니다.

 

 

 처음에, 조건에 맞는지 확인을 합니다. 만약에 맞지 않다면, 예외를 던질 텐데요. radix가 2 미만이거나 36 이상이거나, s가 null이라면, 예외를 던지게 되어 있습니다. 밑에 줄을 계속 봅시다.

 

 

 558번째 줄에 limit라는 친구가 있습니다. Integer.MAX_VALUE의 값이 2148483647인데요. 여기에 -1을 곱했으니까, -2148483647이 되겠네요. 왜 이렇게 set 했는지는 모르겠어요. 일단 계속 봅시다. 562번째 줄에, len이 0보다 크다면, 맨 앞에 있는 문자가 숫자가 아닌 다른 문자가 오는지 먼저 검사할 겁니다.

 

 

 이것을 564번째 줄에서 check 하고 있습니다. 실제로 '0'의 값은 48이지만, '+'는 43, '-'는 45임을 알 수 있어요.

 

 

 그렇기 때문에 firstChar가 '0'보다 작은지만 체크하고 있어요. 그렇다면 +나 -, 둘 중 하나가 앞에 있을 확률이 있을 겁니다. 그렇지 않다면, 앞에 부호가 없을 거니까, 564번째 if문에 걸리지 않습니다. 만약에 있을 가능성이 있다면, 정말로 앞에 오는 것이 vaild한지 검사할 겁니다. 만약에 -가 왔다면, limit는 -2148483648이 됩니다. 그게 아니고, '+'가 앞에 오지 않았다면 invaild 하니까 걸러져야 할 겁니다. 부호만 오는 것도 걸러져야 되는데, 이는 571번째 줄에서 처리하고 있습니다.

 

 즉, 564번째 if문은 앞에 부호가 있는지, 없는지를 검사해서, 있다면 negative flag를 true로 설정하는 역할을 합니다.

 

 


 이제, 정말 입력된 문자열이 Integer 안에 들어오는지 확인을 해야 합니다. 이 과정은 575번째 줄부터 이루어 집니다.

 

 

 digit가 0보다 작다면, 예외를 던집니다. Character의 digit 함수는 어떠한 문자가, 어느 진법에서 어떤 숫자로 대응이 되는지를 리턴해 주는 함수인데요. 만약에 16진법인데 'U'가 들어왔다면 -1이 리턴이 됩니다. 이는 유효하지 않거든요. 반면에, 36진법인데 'u'가 들어왔다면 30이 리턴될 겁니다. 이는 그렇게 크게 어려운 예외가 아닙니다.

 

 그런데, result가 multmin보다 작으면 또 예외를 던지는데요. result가 while문 안에서 어떤 식으로 변하는지 알 필요가 있습니다. 계속 봅시다.

 

 

 

 result에 radix를 곱한 다음에, digit를 계속 빼고 있어요. 예를 들어서, 2138이 들어왔다면 result는 다음과 같이 변할 겁니다. -2, -20, -21, -210, -213, -2130, -2138. 이런 식으로 계속 음수로 변하고 있어요. 그러면 multmin보다 result가 작다는 것은 무엇을 의미할까요?

 

 예를 들어서, 3000000000이 들어왔다고 해 봅시다. 10진수였다고 한다면 multmin은 -214748364였을 겁니다.

 

 

 그러면 8번째 원소까지 모두 검사하고, 589번째 code까지 실행했다면 result에는 -300000000이 저장이 되어 있을 겁니다. 여기까지는 그리 어렵지 않네요. 그런데, len은 10이므로, 뒤에 0 또한 보아야 할 겁니다. 즉, while loop가 1번 더 실행이 됩니다.

 

 

 이 때, -300000000은 -214748364보다 작으므로, int 범위에 들어오지 못합니다. 따라서 예외를 던집니다. 그러면 586번째 줄은 무엇을 의미하는 것일까요? 2147483649를 생각해 봅시다. 이는 int형 범위에 들어오지는 못합니다. 그런데, 노란색까지만 본다면, multmin이 -214748364이고, 585번째 줄을 수행하면, res는 -214748364이기 때문에, -2147483640으로 변경되었기 때문에, 여전히 예외에 걸리지 않습니다.

 

 

 그런데, 문제는 digit가 9입니다. -2147483640에서 9를 빼면 -2147483649인데, 이는 int형 범위에 벗어나 버립니다. 이렇게 오버플로우가 나는 경우에는 어떻게 해야 할까요? res에서 digit를 빼니까 limit보다 작아진 셈인데요. res - digit < limit라는 수식을 바꾸면 res < limit + digit가 됩니다.

 

 이 digit는 0보다 크거나 같고 9보다 작거나 같고, limit는 매우 작은 수이므로, limit + digit는 오버플로우나 언더플로우가 나지 않습니다. 586번째 줄은 -2147483649와 같은 것을 예외 처리하기 위해서 만들어진 거라고 생각하시면 되겠습니다. 전체적인 코드가 이해 가시나요? 흔히 알고 계시는, String을 int로 바꾸는 알고리즘을 쓰고 있어요. 단지, 추가된 것은 오버플로우를 어떻게 잘 처리하느냐일 겁니다.

 

 


 valueOf는 String을 Integer로, 바꿔주는 함수인데요. 물론 Long에도 있습니다. 이것은 String을, 포장된 객체로 바꿔주는 역할을 합니다.

 

 

 이것도 보시면 valueOf라는 녀석을 호출하고 있다는 것을 알 수 있는데요. parseInt를 먼저 호출합니다. parseInt의 리턴 값인 int형을, valueOf에 넘기는데요. 이 함수는 별 다른 것이 없습니다.

 

 

 그냥 새로운 Integer 객체를 리턴하거나, IntegerCache에 있는 것을 리턴해 버립니다. 이 IntegerCache는, 자주 사용하는 포장 객체에 대해서, 미리 저장을 해 놓는 역할을 하는데요. 예를 들어서 -128부터 127까지는 꽤 자주 씁니다. 따라서, 객체 배열에다가 요런 식으로 저장해 놓고, i에 대한 것이 Cache에 저장이 되어 있다면 그것을 불러오는 것입니다. 물론, 이 범위는 따로 설정을 해 줄 수 있습니다.

 

 

 대충 이런 식이에요. 그렇다면, valueOf가 invoke 되기 전에, cache가 초기화가 되어야 겠네요. 그리고, 만약에 cache에 저장이 되어 있지 않으면 계속 새로운 객체를 만들어 내겠네요.

 

 


 

 이제 예제 프로그램을 봅시다. String "20"을 int형으로, 그리고 "337"을 Integer형으로 변환하는 부분 이해 가시나요? 크게 어려운 거 없어요. 그리고, n에다가 u를 대입하고 있는데요. int형에 Integer형을 대입해 버렸습니다. 이를 unboxing이라고 하는데 1.5부터 자동 boxing, unboxing이 지원됩니다. 출력 결과는 20, 337이 나올 거고요.

 

 글이 다소 길었습니다. 정리를 해 봅시다. Java의 parseInt와, valueOf는 int형을 리턴하느냐, 객체를 리턴하느냐 차이가 있어요. 이 부분만 잘 정리를 하신다면, 크게 문제는 없으리라 생각이 듭니다.

반응형

댓글을 달아 주세요

  1. 비밀댓글입니다

  2. 듣는이 - 고민상담, 속풀이, 공감대

    저도 코딩 한 번 공부해보고 싶은데 올려주신 순서대로 공부하면 되는 걸까요..?

    • 코딩강아지
      2019.07.17 19:21 신고

      레퍼런스 카데고리 제외하고는
      공부하시기 쉽게 올릴 생각이에요.

      레퍼런스는 제가 생각나면 올리는지라..
      나중에 이것도 다시 재정비를 해 보겠습니다.