Page tree
Skip to end of metadata
Go to start of metadata

1. "韓 시장 중요하다"는 인스타그램, '인쇼' 부작용 대책은 '글쎄'


지난 3월 3주차 뉴스클리핑에서 다룬 바 있었던, 미국 인스타그램에 시범 적용된 인앱결제 기능이 국내 앱에서도 서비스될 예정입니다. 지난 7일 열린 기자간담회에서 짐 스콰이어스 인스타그램 비지니스 및 미디어 총괄 부사장은 한국이 인스타그램에 주요 전략 시장임을 거듭 강조하며, 한국 시장의 성장 잠재력에 대한 기대감을 드러냈습니다. 이 기대감의 근거로, 최근 시행된 소비자 조사 결과 국내 이용자 51%가 지난 해 대비 인스타그램을 더 많이 쓰고 있고 내년에는 더 많이 쓸 것이라고 응답한 것을 들었습니다. 그러나 인스타그램의 새로운 서비스 방안(좋아요·조회수를 가리는 방안)이 도입될 경우 조사 결과대로 될 것인지는 미지수입니다.

업계는 인스타그램이 소비자 피해 보호 대책과 판매자 탈세 논란에 대해 뚜렷한 대책을 내놓지 못한 데에 우려를 표하고 있습니다. 인스타그램은 최근 있었던 인쇼(인스타그램 쇼핑) 부작용 논란에 있어 구체적인 소비자 피해 대책과 판매자들의 탈세 논란에 대해 "인플루언서 스스로 책임감을 갖고 의무를 다해야 한다"는 원론적인 입장만 드러내며 선을 그었습니다. 과연 인스타그램의 행보가 국내 시장에 좋은 영향을 미칠 수 있을지 우려가 됩니다.




2. Map의 value를 keySet iterator를 이용하여 얻지 말 것


Map에서 key 목록을 이용하여 value를 얻으려 할 때, 많은 개발자들이 다음과 같은 방법을 사용합니다.

public void test(Map<String, String> info){
    for(String key : map.keySet()){
        System.out.println(map.get(key));
    }
}

하지만 이 방법은, key를 얻어오고 다시 한 번 map으로부터 value를 얻어오기 때문에 성능에 심각한 문제가 발생하게 됩니다.

하여 다음과 같은 방법으로 변경하여야 합니다.

public void test(Map<String, String> info){
    for(Map.Entry<String, String> entry : info.entrySet()){
        System.out.println(entry.getValue());
    }
}


3. HashMap의 동작 방법


HashMap이 내부적으로 어떻게 동작하는지에 대한 질문은 면접 때에 가장 인기있는 질문입니다. 대부분의 사람들은 HashMap을 사용할줄 알거나 HashMap과 HashTable의 차이는 알고 있습니다. 그러나 "HashMap이 내부적으로 어떻게 동작하는가?" 에 대한 질문에 대해서는 어려워합니다.

질문에 대한 해답은 해싱 원리에 기반하여 작동한다는 것이지만 말처럼 간단한 문제는 아닙니다. 해싱은 쉽게 반복하는 알고리즘을 사용하면서 유니크한(유일무이한) 코드를 변수 또는 속성에 할당하는 매커니즘으로, 해싱 매커니즘에 같은 객체를 적용시켰을 때, 항상 같은 hashcode()를 반환해야 합니다.

그러면 다음과 같은 질문을 할 수 있습니다.

"해싱이 HashMap에서 저장하고 값을 검색할 수 있도록 할까?"

많은 사람들은 이렇게 대답할 것입니다. "바구니에 값들이 저장될 것이고 키를 통해 검색한다." 만약 당신도 이렇게 생각하고 있었다면 잘못 알고 있었던 것입니다. 그것을 입증하기 위해서 HashMap 클래스를 살펴보겠습니다.

transient Entry[] table;

HashMap에서 Entry[]를 어떻게 사용할까요? HashMap은 키-값 쌍을 저장하는 것이 아니라 Entry 인스턴스와 같은 객체를 저장합니다.


Entity Class란?

HashMap은 키와 값을 가지는 Entry Class를 내부 클래스로 가집니다. 그리고 이 클래스는 next라는 이름을 가지고 있는데 이에 대해서는 곧 설명하겠습니다.

static class Entry<K,V> implements Map.Entry<K,V> {
     final K key;
     V value;
     Entry<K,V> next;
     final int hash;
 }

HashMap이 배열 내에서 키-값의 쌍이 아니라 Entry 인스턴스를 저장한다는 것은 위에서 말했습니다.

값을 저장하기 위해서는 HashMap의 put()메소드를 이용할텐데 지금부터 put() 이 어떻게 동작하는지 파헤쳐 보겠습니다. 

put() 메서드는 내부적으로 어떻게 동작할까?

다음 코드는 put()  메소드의 구현부입니다.

public V put(K key, V value) {
    if (key == null)
       return putForNullKey(value);
 
    int hash = hash(key.hashcode());
    int i = indexFor(hash, table.length);
 
    for (Entry<K,V> e = table[i]; e != null; e = e.next){
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))){
             V oldValue = e.value;
             e.value = value;
             e.recordAccess(this);
             return oldValue;
          }
     }
     modCount++;
     addEntry(hash, key, value, i);
     return null;
 }
  • 먼저, 키가 null인지 체크합니다. 만약 null이면 null의 hashcode는 0이기 때문에 위치 0에 저장합니다.
  • 그런다음 hashcode 메소드를 호출함으로써 hashcode를 적용합니다. 배열의 한도 내에서 값을 얻기 위해서는 key.hashcode() 가 호출되는데 이 때, hashcode에 대해 일부 시프팅 연산을 수행합니다.
  • indexFor() 메소드는 Entry 객체를 저장할 정확한 위치를 가져올 때 사용합니다.
  • 만약 두개의 다른 객체가 같은 hashcode를 가지고 같은 저장소에 저장된다면 아주 중요한 일이 일어납니다. 이를 처리하기 위해 LinkedList에서는 각각이 다음 객체를 가리키는 "next"라는 속성을 가지는데, Entry class에서 next 속성도 같은 역할을 합니다. 같은 hashcode를 가지는 객체들은 서로 옆에 위치합니다. 
  • 그래서 충돌이 났을 때, HashMap은 next 속성의 값을 체크합니다. 만약 null이라면 그 위치에 Entry 객체를 넣고 null이 아니라면 next 객체가 null일 때까지 루프를 돌다가 결국 next 속성이 null이 되면 거기에 Entry 객체를 저장합니다.

HashMap에서 중복되는 키 값을 어떻게 막을까?

HashMap은 중복되는 중복 키를 허용하지 않기 때문에, 동일한 키로 다른 값을 넣는다면 가장 최근 값이 반환됩니다.

import java.util.HashMap;
import java.util.Map;
 
public class HashMapEg{
    public static void main(String[] args) {
            Map map = new HashMap();
            map.put(1,"sam");   
            map.put(1,"Ian");   
            map.put(1,"Scott");   
            map.put(null,"asdf");
 
            System.out.println(map);  
        }
}

위의 코드에서 map은 {null=asdf, 1=Scott} 이 될 것입니다. 어떻게 이런 일이 일어나는 것일까요?

LinkedList에서 모든 Entry객체들은 같은 hashcode를 가집니다. 그러나 HashMap은 equals()를 사용합니다. 이 메소드는 키의 값이 동일한지를 체크하는 것이고 따라서 key.equals(other key) 가 true이면 Entry class 내부의 값이 대체 됩니다. 그래서 중복 키를 방지할 수 있습니다. 


Get메서드는 내부적으로 어떻게 동작할까?

put() 메소드에서 적용했던 것과 유사하게, 로직이 값을 검색하는데에도 사용됩니다.

public V get(Object key) {
    if (key == null)
       return getForNullKey();
 
     int hash = hash(key.hashcode());
     for (Entry<K,V> e = table[indexFor(hash, table.length)];e != null;e = e.next){
         Object k;
         if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
             return e.value;
     }
         return null;
 }
  • 먼저, 전달된 키 객체의 hashcode를 가져와서 버킷 위치를 찾습니다.
  • 만약 찾으면 그 값을 반환합니다.
  • 찾지 못하면 null을 반환합니다..

만약 두 키가 같은 해시코드를 가진다면 어떻게 될까?

put() 메소드 내에서 hashcode 값이 동일할 경우 충돌이 발생했을 때 해결했던 매커니즘이 동일하게 여기서 사용됩니다.

key.equals(other key)가 true일 때까지 검사하고, true인 경우 값을 반환합니다. 



References


Related Information


There is no content with the specified labels

  • No labels