JAVA 교체 기 깊이 이해

8986 단어 JAVA
교체 기 모드:용기 대상 의 각 요 소 를 방문 하고 대상 용기 의 내부 디 테 일 을 드 러 내지 않 는 방법 을 제공 하 는 것 입 니 다.
개술
자바 집합 프레임 의 집합 류 를 우 리 는 때때로 용기 라 고 부른다.용기 의 종 류 는 여러 가지 가 있 습 니 다.예 를 들 어 Array List,LinkedList,HashSet...............................................................링크 드 리스트 는 링크 구조 입 니 다.HashSet 은 해시 표 에 의존 하 며 모든 용기 에는 자신 만 의 데이터 구조 가 있다.
용기 의 내부 구조 가 다 르 기 때문에 한 용기 의 요 소 를 어떻게 옮 겨 다 녀 야 할 지 모 를 때 가 많 습 니 다.그래서 용기 내 요소 에 대한 조작 을 더욱 간단하게 하기 위해 자바 는 교체 기 모드 를 도입 하 였 습 니 다! 
방문 논 리 를 서로 다른 유형의 집합 류 에서 추출 하여 외부 로 집합 하 는 내부 구 조 를 노출 시 키 지 않도록 한다.
배열 에 대해 우 리 는 아래 표 시 를 사용 하여 처리 합 니 다.
1 int array[] = new int[3];    
2 for (int i = 0; i < array.length; i++) {
3     System.out.println(array[i]);
4 }

Array List 처리
1 List list = new ArrayList();
2        for(int i = 0 ; i < list.size() ;  i++){
3           String string = list.get(i);
4 }

이 두 가지 방식 에 대해 우 리 는 항상 그의 내부 구 조 를 알 고 방문 코드 와 집합 자체 가 밀접 하 게 결합 되 어 방문 논 리 를 집합 류 와 클 라 이언 트 코드 에서 분리 할 수 없다.서로 다른 집합 은 서로 다른 옮 겨 다 니 는 방법 에 대응 하여 클 라 이언 트 코드 를 재 활용 할 수 없습니다.실제 응용 에서 위의 두 집합 을 어떻게 통합 하 는 지 는 상당히 번거롭다.그래서 Iterator 가 있 습 니 다.항상 같은 논리 로 집합 합 니 다.클 라 이언 트 자체 가 집합 한 내부 구 조 를 유지 할 필요 가 없고 모든 내부 상 태 는 Iterator 가 유지 합 니 다.클 라 이언 트 는 집합 과 직접 접촉 하지 않 고 Iterator 가 앞으로 나 아 가 는 명령 을 보 내 면 집합 을 옮 겨 다 닐 수 있 습 니 다.
1.java.util.Iterator
자바 의 Iterator 인터페이스 가 어떻게 실현 되 는 지 살 펴 보 자.
자바 에서 Iterator 는 하나의 인터페이스 로 교체 의 기본 규칙 만 제공 합 니 다.JDK 에 서 는 Collection 을 교체 하 는 교체 기 라 고 정의 합 니 다.교체 기 는 자바 Collection Framework 의 Enumeration 을 대체 했다.교체 기 는 매 거 진 것 과 두 가지 가 다르다.
1.교체 기 는 교체 기간 에 집합 에서 원 소 를 제거 할 수 있다.
2.방법 명 이 개선 되 었 고 Enumeration 의 방법 명 이 비교적 길다.
그 인터페이스 정 의 는 다음 과 같다.
package java.util;
public interface Iterator {
    boolean hasNext();//             

    E next();//       

    void remove();//    
}

2.Iterable
자바 에 서 는 Iterable 인터페이스 도 제공 합 니 다.Iterable 인터페이스 가 실 현 된 후의 기능 은'되 돌아 가기'의 교체 기 입 니 다.우 리 는 이 인터페이스의 하위 인 터 페 이 스 를 자주 실현 합 니 다.Collection,List,Set 등 이 있 습 니 다.이 인터페이스의 iterator()방법 은 표준 Iterator 로 되 돌아 갑 니 다.Iterable 인터페이스 허용 대상 이 Foreach 문장의 목표 가 되도록 합 니 다.foreach 문 구 를 통 해 바 텀 시퀀스 를 옮 겨 다 닐 수 있 습 니 다.
Iterable 인 터 페 이 스 는 Iterator 대상 을 만 들 수 있 는 방법 을 포함 하고 Iterable 은 foreach 에 의 해 시퀀스 에서 이동 합 니 다.따라서 Iterable 인 터 페 이 스 를 실현 하 는 클래스 를 만 들 면 foreach 에 사용 할 수 있 습 니 다.
Iterable 인터페이스의 구체 적 인 실현:
Package java.lang;

import java.util.Iterator;
public interface Iterable {
    Iterator iterator();
}

교체 기 를 사용 하여 집합 을 옮 겨 다 니 기:
 1 public static void main(String[] args) {
 2         List list = new ArrayList();
 3         list.add("  1");
 4         list.add("  2");
 5         list.add("  3");
 6         list.add("  4");
 7         
 8         List linkList = new LinkedList();
 9         linkList.add("link1");
10         linkList.add("link2");
11         linkList.add("link3");
12         linkList.add("link4");
13         
14         Set set = new HashSet();
15         set.add("set1");
16         set.add("set2");
17         set.add("set3");
18         set.add("set4");
19         //       ArrayList  
20         Iterator listIt = list.iterator();
21         while(listIt.hasNext()){
22             System.out.println(listIt.next());
23         }
24         //       Set  
25         Iterator setIt = set.iterator();
26         while(setIt.hasNext()){
27             System.out.println(listIt.next());
28         }
29         //       LinkedList  
30         Iterator linkIt = linkList.iterator();
31         while(linkIt.hasNext()){
32             System.out.println(listIt.next());
33         }
34 }

foreach 를 사용 하여 집합 을 옮 겨 다 니 기:
        List list = new ArrayList();
        list.add("  1");
        list.add("  2");
        list.add("  3");
        list.add("  4");
        for (String string : list) {
            System.out.println(string);
        }

이 를 통 해 알 수 있 듯 이 foreach 를 사용 하여 집합 을 옮 겨 다 니 는 장점 은 코드 가 더욱 간결 하고 실수 하기 쉽 지 않 으 며 아래 표 시 된 시작 값 과 종료 값 에 관심 을 가지 지 않 아 도 된다 는 것 이다.
 3.Iterator 를 옮 겨 다 닐 때 집합 에 있 는 요 소 를 삭제 할 수 없습니다.
 Iterator 를 사용 할 때 옮 겨 다 니 는 용기 의 크기 구 조 를 바 꾸 는 작업 을 금지 합 니 다.예 를 들 어 Iterator 를 사용 하여 교체 할 때 집합 에 add,remove 작업 을 하면 Concurrent ModificationException 이상 이 발생 합 니 다.
 
 1         List list = new ArrayList();
 2         list.add("  1");
 3         list.add("  2");
 4         list.add("  3");
 5         list.add("  4");
 6         
 7         //       ArrayList  
 8         Iterator listIt = list.iterator();
 9         while(listIt.hasNext()){
10             Object obj = listIt.next();
11             if(obj.equals("  3")){
12                 list.remove(obj);
13             }
14         }

교체 하기 전에 교체 기 는 list.itertor()를 통 해 만 들 어 졌 기 때문에 교체 과정 에서 list 에 대해 용기 크기 를 바 꾸 는 작업 을 하면 자바 가 이상 을 줄 수 있 습 니 다.이 때 Iterator 대상 이 list 의 변 화 를 주동 적 으로 동기 화 할 수 없 기 때문에 자바 는 이러한 조작 을 하 는 것 이 스 레 드 가 안전 하지 않다 고 생각 하고 선의 의 알림 을 줄 것 입 니 다(Concurrent ModificationException 이상 을 던 집 니 다)
Iterator 의 실현 소스 코드:
 1     private class Itr implements Iterator {
 2         int cursor;       // index of next element to return
 3         int lastRet = -1; // index of last element returned; -1 if no such
 4         int expectedModCount = modCount;
 5 
 6         public boolean hasNext() {
 7             return cursor != size;
 8         }
 9 
10         @SuppressWarnings("unchecked")
11         public E next() {
12             checkForComodification();
13             int i = cursor;
14             if (i >= size)
15                 throw new NoSuchElementException();
16             Object[] elementData = ArrayList.this.elementData;
17             if (i >= elementData.length)
18                 throw new ConcurrentModificationException();
19             cursor = i + 1;
20             return (E) elementData[lastRet = i];
21         }
22 
23         public void remove() {
24             if (lastRet < 0)
25                 throw new IllegalStateException();
26             checkForComodification();
27 
28             try {
29                 ArrayList.this.remove(lastRet);
30                 cursor = lastRet;
31                 lastRet = -1;
32                 expectedModCount = modCount;
33             } catch (IndexOutOfBoundsException ex) {
34                 throw new ConcurrentModificationException();
35             }
36         }
37 
38         final void checkForComodification() {
39             if (modCount != expectedModCount)
40                 throw new ConcurrentModificationException();
41         }
42     }

원본 코드 를 확인 한 결과 원래 검 사 를 하고 이상 을 던 지 는 것 은 checkForComodification()방법 입 니 다.Array List 에서 modCount 는 현재 집합 한 버 전 번호 로 수정(추가,삭제)집합 할 때마다 1 을 추가 합 니 다.expected ModCount 는 현재 교체 기의 버 전 번호 로 교체 기 를 예화 할 때 modCount 로 초기 화 합 니 다.checkForComodification()방법 에서 modCount 의 값 과 expected ModCount 의 값 이 같은 지 검증 하 는 것 을 보 았 습 니 다.그래서 Array List.add()나 Array List.remove()를 호출 했 을 때 modCount 의 상태 만 업 데 이 트 했 고 교체 기 에 있 는 expected ModCount 가 동기 화 되 지 않 아 Iterator.next()방법 을 다시 호출 할 때 이상 을 던 졌 습 니 다.그런데 왜 Iterator.remove()를 사용 하면 문제 가 없 을까요?원본 코드 32 줄 을 통 해 Iterator 의 reove()에서 expected ModCount 의 값 을 동기 화 했 기 때문에 다음 에 next()를 호출 할 때 이상 이 없 는 지 확인 합 니 다.
이 메커니즘 을 사용 하 는 주요 목적 은 ArrayList 의 빠 른 실패 메커니즘(fail-fast)을 실현 하기 위해 서 이다.자바 집합 에서 비교적 큰 부분 집합 은 빠 른 실패 메커니즘 이 존재 한다.
빠 른 실패 메커니즘 이 발생 하 는 조건:여러 스 레 드 가 Collection 을 조작 할 때 한 스 레 드 가 Iterator 를 통 해 집합 을 옮 겨 다 닐 때 이 집합 내용 이 다른 스 레 드 에 의 해 바 뀌 면 Concurrent ModificationException 이상 을 던 집 니 다.
따라서 Iterator 를 사용 하여 집합 을 옮 겨 다 닐 때 오류 가 발생 하지 않도록 집합 을 옮 겨 다 니 는 과정 에서 집합 에 구조 적 인 수정 이 일어나 지 않도록 해 야 한다.
 Foreach 를 사용 할 때 집합 구 조 를 수정 하면 이상 이 발생 합 니 다.
위 에서 말 했 듯 이 Iterable 인 터 페 이 스 를 실현 하 는 종 류 는 Foreach 를 통 해 옮 겨 다 닐 수 있다.그것 은 foreach 가 Iterable 인터페이스 에서 돌아 오 는 Iterator 대상 에 의존 해 야 하기 때문에 본질 적 으로 Foreach 는 교체 기 를 사용 하고 foreach 를 사용 할 때 집합 구 조 를 수정 하 는 것 이다.Iterator 를 사용 할 때 집합 구 조 를 수정 하 는 것 과 본질 적 으로 같다.그래서 똑 같이 이상 을 던 지고 빠 른 실패 체 제 를 집행 한다.
foreach 는 JDK 1.5 에 새로 추 가 된 순환 구조 로 foreach 의 등장 은 우리 가 집합 하 는 행 위 를 간소화 하기 위 한 것 이다.
 for 순환 과 교체 기의 대비:
  * 효율 적 으로 각각 장점 이 있다.
    > Array List 는 무 작위 접근 이 빠 르 고 for 순환 에서 사용 하 는 get()방법 은 무 작위 접근 방법 을 사용 하기 때문에 Array List 에서 for 순환 이 빠르다.
    > LinkedList 는 순서 접근 이 빠 르 고 Iterator 의 next()방법 은 순서 접근 방법 을 사용 하기 때문에 LinkedList 에서 Iterator 를 사용 하 는 것 이 빠르다.
    > 주로 집합 한 데이터 구조 에 따라 다른 판단 을 해 야 한다.

좋은 웹페이지 즐겨찾기