2017-12-13 13 views
1

클래스의 소스 코드를 확인합니다. 나는 목록이 가능해, RandomAccess 유형의 경우 우리가 확인하는 이유를 알아 보았 실패Collections.synchronizedList (list)가 내부적으로 instanceof check를 사용하는 이유는 무엇입니까?

public static <T> List<T> synchronizedList(List<T> list) { 
    return (list instanceof RandomAccess ? 
      new SynchronizedRandomAccessList<>(list) : 
      new SynchronizedList<>(list)); 
} 

방법 에는 Collections.synchronizedList (목록)을 가로 질러왔다. ArrayList가이 인터페이스를 구현하고 LinkedList가 구현하지 않는다는 것을 이해합니다. 또한

, SynchronizedRandomAccessListSynchronizedList을 상속합니다. 그러면이 수표의 요점은 무엇입니까? 설명해주세요.

+2

문자열 객체를 상속 → 진정한

System.out.println( Collections.synchronizedList(Collections.checkedList(new LinkedList<>(), String.class)) instanceof RandomAccess); 

System.out.println( Collections.synchronizedList(Collections.checkedList(new ArrayList<>(), String.class)) instanceof RandomAccess); 

당신이 더 String 클래스가 없어야 의미 생각 ... : 공장을 결합 할 때 그래서 심지어 작동? – Stultuske

+0

특정의'List' 구현이 마커 인터페이스'RandomAccess'를 구현하고 있기 때문에 효율적인 랜덤 액세스를 제공하는리스트 구현에 대해보다 효율적일 수있는'SynchronizedRandomAccessList'를 반환해야합니다. 리스트가 랜덤 액세스를 제공하지 않으면'SynchronizedList'가 사용되어야합니다. – Jesper

+0

@ Stultuske 내 질문에 왜 우리는 instanceof 체크 –

답변

5

거의 다 왔어. 일부 목록에는 RandomAccess을 구현하기 때문에 Collections.synchronizedList(list)RandomAccess을 확인합니다.

RandomAccess은 과 마찬가지로 marker interface입니다. 목록의 항목에 임의로 액세스 할 수 있는지 여부를 알려줍니다. 나는. ArrayList에서 동일한 계산 비용으로 모든 항목을 검색 할 수 있습니다. 반면에 n 번째 요소를 찾으려면 LinkedList을 따라 가야합니다.

그럼 Collections.synchronizedList(list)에는 어떤 현상이 발생합니까? RandomAccessList -s를 RandomAccess 동기화 목록에 래핑하는 반면, RandomAccess 목록을 RandomAccess 동기화 목록으로 래핑합니다. 그렇지 않으면 그 목록은 동일합니다. 아래 코드는 SynchronizedRandomAccessList입니다. 이것은 programming by difference의 좋은 예입니다. 두 클래스는 거의 동일합니다.

static class SynchronizedRandomAccessList<E> 
    extends SynchronizedList<E> 
    implements RandomAccess { 

    SynchronizedRandomAccessList(List<E> list) { 
     super(list); 
    } 

    SynchronizedRandomAccessList(List<E> list, Object mutex) { 
     super(list, mutex); 
    } 

    public List<E> subList(int fromIndex, int toIndex) { 
     synchronized (mutex) { 
      return new SynchronizedRandomAccessList<>(
       list.subList(fromIndex, toIndex), mutex); 
     } 
    } 

    private static final long serialVersionUID = 1530674583602358482L; 

    /** 
    * Allows instances to be deserialized in pre-1.4 JREs (which do 
    * not have SynchronizedRandomAccessList). SynchronizedList has 
    * a readResolve method that inverts this transformation upon 
    * deserialization. 
    */ 
    private Object writeReplace() { 
     return new SynchronizedList<>(list); 
    } 
} 

RandomAccess 인터페이스의 요점은 무엇입니까? Holger이 지적했듯이 Collections.binarySearch()은이 인터페이스를 기반으로 결정합니다. 또 다른 예는 Collections.reverse()입니다.

+0

다른 잠금 모델은 없습니다. 메소드 이름에서 알 수 있듯이 둘 다'synchronized'를 사용하고 [documentation] (https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedList-java.util.List -)를 지정합니다. – Holger

+0

비 특정 문구를 사용했습니다. 두 클래스 모두'SynchronizedRandomAccessList'와'SynchronizedList'는 잠금을 다르게 관리합니다. 이것이 제가 언급 한 것입니다. –

+0

그들은 어떤 방식으로 잠금 장치를 다르게 관리합니까? – Holger

3

RandomAccess 마커 인터페이스의 원래 목적을 기억해야합니다. List을 다른 방법으로 전달하면 임의 액세스 또는 순차적 목록에 적합한 알고리즘을 선택할 수 있어야합니다. 올바른 알고리즘을 선택하려면 list instanceof RandomAccess을 통해 마커 인터페이스를 테스트해야합니다.

방금, 이러한 모든 방법을 볼 수있는 List 인터페이스를 구현하는 다른 객체로 목록을 포장하는 경우 one example

public static <T> 
int binarySearch(List<? extends Comparable<? super T>> list, T key) { 
    if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD) 
     return Collections.indexedBinarySearch(list, key); 
    else 
     return Collections.iteratorBinarySearch(list, key); 
} 

는 지금

(또한 reverse, shuffle, copyfill 참조) 표시하려면 , 래퍼 개체이므로이 정보는 손실됩니다. 그러나 동기화 된 목록과 같은 래퍼는 get과 같은 임의 액세스 방법의 시간 복잡도를 변경하지 않습니다. 따라서 래핑 된 목록이 임의 액세스 목록 인 경우 래퍼는 RandomAccess도 구현해야하므로 이러한 래퍼를 수신하는 메서드는 빠른 임의 액세스를 사용할 수 있는지 여부를 여전히 감지 할 수 있습니다.

당신이 implementation of SynchronizedRandomAccessList 보면, 당신이하지 모두가 SynchronizedList을 확장하고 동작을 상속, RandomAccess 구현 및 빠른 랜덤 액세스를 필요로 자신을 표시되는 것을 볼 수 있습니다. 재정의하는 유일한 방법은 정확히 같은 이유로 subList입니다. 목록에 효율적인 무작위 액세스가있는 경우 해당 하위 목록도 있으므로 RandomAccess도 구현해야합니다. checkedList 같은 다른 래퍼 공장 같은 패턴을 따르는 것이

static class SynchronizedRandomAccessList<E> 
    extends SynchronizedList<E> 
    implements RandomAccess { 

    SynchronizedRandomAccessList(List<E> list) { 
     super(list); 
    } 

    SynchronizedRandomAccessList(List<E> list, Object mutex) { 
     super(list, mutex); 
    } 

    public List<E> subList(int fromIndex, int toIndex) { 
     synchronized (mutex) { 
      return new SynchronizedRandomAccessList<>(
       list.subList(fromIndex, toIndex), mutex); 
     } 
    } 

참고. 거짓

+0

기본적으로 더 나은 접근 방법을 구별하고 구별하는 방법은 무엇입니까? – Eugene

+1

@Eugene : 예. 이것이 처음부터, 즉 Java 1.2에서 고려 되었다면, 아마도 소스리스트에 위임함으로써 구현 될 수있는'List.isRandomAccess()'메소드를 생성했을 것입니다. 안타깝게도이 문제는 간과되었고'RandomAccess' 마커 인터페이스가 1.4에 추가되었습니다 (1.8에 추가 되었으면 '기본'메소드가 옵션이었습니다). – Holger

+0

답을 읽은 후에는 아무 것도 열심히 질문하지 않는 것 같습니다. 고마워 – Eugene