top bar

글 목록

2015년 6월 16일 화요일

[JAVA] List - ArrayList

List 개요



 아마도, JAVA 개발자들이 가장 많이 쓰는 컨테이너 중에 하나일 듯 싶다. List는 특별한 시퀀스(Sequence)로 객체들을 유지, 관리한다.

List는 두가지 타입이 있다.

ArrayList
LinkedList
요소(객체)들을 무작위로 Access하는데 O(1)의 시간으로 속도 면에서 탁월하다. 하지만 중간에 요소들을 추가하거나 삭제할 때는 효율이 별로 좋지 않다.
최적의 순차 Access를 제공하며, 중간에 요소 추가/삭제 면에서 ArrayList보다 훨씬 빠른 속도를 보인다. 반면에 무작위 Access ArrayList보다는 느리다.


예제 - ArrayList



 List인터페이스는 매우 다양한 메소드를 제공한다. 예제를 통해 각 메소드들을 이해하도록 하자. 이제부터 ArrayList의 메소드들을 살펴본다.

※ 예제에는 Pet(애완동물)클래스의 다양한 서브클래스를 이용해 생성된 객체들을 가지고 테스트 해본다. 예제에서 Pets.arrayList() 메소드는 무작위로 선택된 Pet객체들로 채워진 ArrayList를 반환한다.

1) add , contains , remove
List<Pet> pets = Pets.arrayList(7);
        
print("1: " + pets);
Hamster h = new Hamster();

pets.add(h);
        
print("2: " + pets);
print("3: " + pets.contains(h));

pets.remove(h);

print("4: " + pets);
print("5: " + pets.contains(h));
> 결과
1: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
2: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Hamster]
3: true
4: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
5: false
7개의 Pet 객체들로 채워진 pets 라고하는 ArrayList가 만들어졌다. 거기에 add 메서드로 'Hamster'의 인스턴스 'h'를 추가했고(여기서 ArrayList의 크기는 자동으로 조절된다), contains 메서드로 인스턴스인 'h'가 존재하는지 확인했다.

그 후에 추가했던 'h'를 remove 메서드를 이용해 삭제하고, 다시 리스트 내용과 contains메서드 결과를 보면 제대로 삭제 된것을 확인 할 수 있다.

add 메서드는 아래와같이 쓸 수도 있다.
pets.add(3, new Hamster());
> 결과
[Rat, Manx, Cymric, Hamster, Mutt, Pug, Cymric, Pug]
첫번째 파라메터는 추가되는 객체가 들어갈 index이고, 두번째 파라메터는 추가되는 객체를 나타낸다. 결과를보면 index 3에 Hamster 객체가 추가된것을 볼 수 있다.

2) get , indexOf
List<Pet> pets = Pets.arrayList(7);

print("1: " + pets);

Pet p = pets.get(2);
print("2: " + p + " " + pets.indexOf(p));
        
Pet cymric = new Cymric();
print("3: " + pets.indexOf(cymric));
> 결과
1: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
2: Cymric 2
3: -1
get 메서드는 파라메터로 넘어간 index의 객체를 반환한다. 여기서는 'Cymric' 객체가 반환된다. indexOf 메서드는 파라메터로 넘어간 객체가 해당 리스트에서 몇번째 인덱스인지에 대한 int값을 반환한다. 여기서는 index '2'에 위치해 있는것을 알 수 있다.

하지만 3번의 결과에서 같은 'Cymric' 객체를 만들어 indexOf를 호출해보면 해당 객체의 위치를 찾지 못하고 '-1'을 반환한다. 왜일까?

이유는 indexOf 메서드는 파라메터로 넘어간 객체의 '주소값'을 해당 리스트 객체의 주소값과 매칭시킨다. (contains 메서드도 마찬가지) 때문에 같은 클래스로부터 생성된 객체라도 주소값이 다르기때문에 다른 객체로 인식이 되는 것이다. 같은 클래스의 객체를 무조건 같은 객체로 인식하게 하고싶다면, 'equals' 메서드를 오버라이딩 하자.

3) subList , containsAll , removeAll
List<Pet> pets = Pets.arrayList(7);

List<Pet> sub = pets.subList(1, 4);

print("1: " + pets);
print("subList: " + sub);
print("2: " + pets.containsAll(sub));

pets.removeAll(sub);
print("3: " + pets);
> 결과
1: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
subList: [Manx, Cymric, Mutt]
2: true
3: [Rat, Pug, Cymric, Pug]
subList 메서드는 말그대로 해당 리스트에서 지정된 범위 만큼 복사하여 새로운 리스트를 생성한다. 위의 예제의 범위는 index '1'부터 '4'전까지 이다.

containsAll 메서드는 말그대로 파라메터로 넘어간 리스트가 해당 리스트에 존재하는지의 여부를 반환한다. 여기서 중요한건, 요소의 순서와는 무관하다는 것이다.

removeAll 메서드는 역시 말그대로 파라메터로 넘어간 리스트를 pets리스트에서 제거한다. 역시 순서는 중요하지 않다.

4) addAll , clear , isEmpty
List<Pet> pets = Pets.arrayList(7);
print("1: " + pets);

List<Pet> newPets = Pets.arrayList(3);      
print("2: " + newPets);
        
pets.addAll(newPets);       
print("3: " + pets);

pets.clear();
print("4: " + pets.isEmpty());
> 결과
1: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
2: [Manx, Cymric, Rat]
3: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Manx, Cymric, Rat]
4: true
addAll 메서드는 말그대로 파라메터로 넘어온 리스트를 합친다. 3번 결과를 보면 1번과 2번 결과가 합쳐진 것을 볼 수 있다.

clear 메서드는 리스트의 내용물을 모두 지우는 메서드이고, isEmpty 메서드는 해당 리스트가 비어있는지 여부를 반환한다.

여기서 addAll 메서드는 아래와 같이 쓰일 수도있다.
pets.addAll(3, newPets);
add 메서드때와 같이 첫번째 파라메터로 넘어온 인덱스부터 합치려는 리스트를 끼워 넣는다. 결과는 알아서 확인하시길..

5) retainAll
List<Pet> pets = Pets.arrayList(7);     
print("1: " + pets);

List<Pet> sub = Arrays.asList(pets.get(0), pets.get(4));
print("sub: " + sub);
        
pets.retainAll(sub);
print("2: " + pets);
> 결과
1: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
sub: [Rat, Pug]
2: [Rat, Pug]
retainAll 메서드는 말하자면 '교집합' 이다. 위의 예제에서는, pets 리스트의 0번째 요소와 4번째 요소로 sub 리스트를 만들었고, retainAll 메서드를 이용, pets와 sub리스트중 겹치는 요소만 pets에 남겼다. 2번결과를 보면 알 수 있다.




댓글 없음:

댓글 쓰기