Chap 12. 컬렉션 프레임워크 [Do it! 자바 프로그래밍 입문]

doriskim·2022년 12월 21일

*본 내용은 [Do it! 자바 프로그래밍 입문] 책과 강의를 보고 공부하면서 요점 정리한 내용입니다.

◼ 제네릭

✔ 제네릭(Generic) 프로그래밍

  • 여러 자료형이 대체될 수 있도록 프로그래밍하는 방식
    참조자료형에서만 사용

  • 변수의 선언이나 메서드 매개변수를 하나의 참조 자료형이 아닌 여러 자료형을 변환될 수 있도록 프로그래밍하는 방식

  • 실제 사용되는 참조 자료형으로의 변환은 컴파일러가 검증하므로 안정적인 프로그래밍 방식

  • 컬렉션 프레임워크에서 많이 사용되고 있음

✔ 제네릭 클래스 정의하기

  • 여러 참조 자료형으로 대체될 수 있는 부분을 하나의 문자로 표현
    이 문자를 자료형 매개변수라고 함

[Object 사용]
ThreeDPrinter.java

package generics;

public class ThreeDPrinter {

	private Object material;

	public Object getMaterial() {
		return material;
	}

	public void setMaterial(Object material) {
		this.material = material;
	}
	
}

ThreeDPrinterTest.java

package generics;

public class ThreeDPrinterTest {

	public static void main(String[] args) {

		ThreeDPrinter printer = new ThreeDPrinter();
		
		printer.setMaterial(new Powder());
		
		Powder powder = (Powder)printer.getMaterial(); // 명시적 형 변환 필요
	}

}

[제네릭 클래스 사용]
ThreeDPrinter.java

package generics;

public class ThreeDPrinter<T> {

	private T material;

	public T getMaterial() {
		return material;
	}

	public void setMaterial(T material) {
		this.material = material;
	}
	
}

ThreeDPrinterTest.java

package generics;

public class ThreeDPrinterTest {

	public static void main(String[] args) {

		ThreeDPrinter<Powder> printer = new ThreeDPrinter<Powder>();
		
		printer.setMaterial(new Powder());
		
		Powder powder = printer.getMaterial(); // 명시적 형 변환 필요X
	}

}

✔ 자료형 매개변수 T

  • type의 의미로 T를 많이 사용함 (element의 의미로 E, value의 의미로 V도 많이 사용)
  • <T>에서 <>는 다이아몬드 연산자라고 함
  • static 키워드는 T에 사용할 수 없음
  • 다이아몬드 연산자 내부에서 자료형은 생략 가능함
ArrayList<String>list = new ArrayList<>();
  • 제네릭에서 자료형 추론 (자바10부터)
ArrayList<String> list = new ArrayList<String>();
↓
var list = new ArrayList<String>();

✔ 제네릭 클래스 사용 예제

  • T로 정의한 부분에 사용할 참조 자료형을 넣어서 클래스 생성
    getMaterial()메서드가 호출될 때 따라 강제 형변환을 하지 않아도 됨
용어설명
GenericPrinter<Powder>제네릭 자료형(Generic type), 매개변수화된 자료형(parameterized type)
Powder대입된 자료형
  • <T extends 클래스>
    T가 사용될 클래스를 제한하기위해 사용
    Material에서 상속받지 않은 Water와 같은 클래스는 프린터 재료로 사용할 수 없음
    Material에 정의된 메서드를 공유할 수 있음

Plastic.java

package generics;

public class Plastic extends Material{

	public String toString() {
		return "재료는 Plastic 입니다.";
	}

	@Override
	public void doPrinting() {
		System.out.println("Plastic 재료로 출력합니다.");
	}
}

Powder.java

package generics;

public class Powder extends Material{
	
	public String toString() {
		return "재료는 Powder 입니다.";
	}

	@Override
	public void doPrinting() {
		System.out.println("Powder 재료로 출력합니다.");
	}
}

Water.java

package generics;

public class Water {
	
	public String toString() {
		return "재료는 Water 입니다.";
	}
}

Material.java

package generics;

public abstract class Material {
	//제한 만들고 싶을 때 상위 클래스 만들어 상속 받기
	
	public abstract void doPrinting();

}

ThreeDPrinter.java

package generics;

public class ThreeDPrinter<T extends Material> {

	private T material;

	public T getMaterial() {
		return material;
	}

	public void setMaterial(T material) {
		this.material = material;
	}

	@Override
	public String toString() {
		return material.toString();
	}
	
	public void printing() {
		material.doPrinting();
	}
	
}

ThreeDPrinterTest.java

package generics;

public class ThreeDPrinterTest {

	public static void main(String[] args) {

		ThreeDPrinter<Powder> printer = new ThreeDPrinter<Powder>();
		printer.setMaterial(new Powder());
		Powder powder = printer.getMaterial();
		System.out.println(printer);
		
		ThreeDPrinter<Plastic> printerPlastic = new ThreeDPrinter<Plastic>();
		printerPlastic.setMaterial(new Plastic());
		Plastic plastic = printerPlastic.getMaterial();
		System.out.println(printerPlastic);
		
		//Material을 상속 받으므로 Water 사용할 수 없어짐
//		ThreeDPrinter<Water> printerWater = new ThreeDPrinter<Water>();
//		printerWater.setMaterial(new Water());
//		System.out.println(printerWater);
		
		printer.printing();
		printerPlastic.printing();
		
	}

}

실행 결과

재료는 Powder 입니다.
재료는 Plastic 입니다.
Powder 재료로 출력합니다.
Plastic 재료로 출력합니다.

✔ 제네릭에서 대입된 자료형을 명시하지 않는 경우

명시하지 않으면 Object로 간주
GenericPrinter<Powder>와 같이 사용할 자료형 (Powder)를 명시해야함
자료형을 명시하지 않고 사용할 수 있음 이런 경우 자료형을 명시하라는 경고표시가 나타남
반환형에 따라 강제 형변환을 해야함

ArrayList list = new ArrayList(); 

✔ 제네릭 메서드

메서드의 매개변수를 자료형 매개변수로 사용하는 경우
[자료형 매개변수가 하나 이상인 경우]

제네릭 메서드의 일반 형식

public <자료형매개변수> 반환형 메서드이름 ( 자료형매개변수 ... ) {}

[자료형 매개변수가 두 개인 경우]
T, V 두 개의 자료형 매개변수 사용

-제네릭 메서드 구현하기
사각형의 너비를 구하는 메서드
두 점의 위치가 여러 자료형으로 사용되는 경우

Point.java

public class Point<T, V>{
	T x;
	V y;
	
    Point(T x, V y){
    	this.x = x;
        this.y = y;
    }
    
    public T getX(){
    	return x;
    }
    
    public V getY(){
    	return y;
    }   
}

GenericMethod.java

public class GenericMethod{
	public static <T, V> double makeRectangle(Point<T, V> p1, Point<T, V> p2){
    	double left = ((Number)p1.getX()).doubleValue();
       	double right = ((Number)p2.getX()).doubleValue();
    	double top = ((Number)p1.getY()).doubleValue();
    	double bottom = ((Number)p2.getY()).doubleValue();
        
        double width = right - left;
        double height = bottom - top;
        
        return width * height;
    }
    public static void main(String[] args){
    	Point<Integer, Double> p1 = new Point<Integer, Double>(0, 0.0);
       	Point<Integer, Double> p2 = new Point<>(10, 10.0);
        
        double rect = GenericMethod.<Integer, Double>makeRectangle(p1, p2);
        System.out.println("두 점으로 만들어진 사각형의 넓이는 " + rect + "입니다.");
    }

}

◼ 컬렉션 프레임워크

✔ 컬렉션 프레임워크

  • 프로그램 구현에 필요한 자료구조(Data Structure)를 구현해놓은 라이브러리
  • java.util 패키지에 구현되어 있음
  • 개발에 소요되는 시간을 절약하면서 최적화된 알고리즘을 사용할 수 있음
  • 여러 인터페이스와 구현 클래스 사용 방법을 이해해야 함

◼ Collection 인터페이스

  • 하나의 객체를 관리하기 위한 메서드가 선언된 인터페이스
  • 하위에 List와 Set 인터페이스가 있음
  • 여러 클래스들이 Collection 인터페이스를 구현함
분류설명
List 인터페이스순서가 있는 자료 관리, 중복 허용.
이 인터페이스를 구현한 클래스는 ArrayList, Vector, LinkedList, Stack, Queue 등이 있음
Set 인터페이스순서가 정해져 있지 않음. 중복을 허용하지 않음.
이 인터페이스를 구현한 클래스는 HashSet, TreeSet등이 있음
  • Collection 인터페이스에 선언된 주요 메서드
메서드설명
boolean add(E e)Collection에 객체를 추가합니다.
void clear()Collection의 모든 객체를 제거합니다.
Iterator<E> iteratorCollection을 순환할 반복자(Iterator)를 반환합니다.
boolean remove(Object o)Collection에 매개변수에 해당하는 인스턴스가 존재하면 제거합니다.
int sizeCollection에 있는 요소의 개수를 반환합니다.

※ 이클립스에서 F1을 눌러 자세한 설명을 볼 수 있다.


✔ List 인터페이스

  • Collection 인터페이스
  • 객체를 순서에 따라 저장하고 관리하는데 필요한 메서드가 선언된 인터페이스
  • 배열의 기능을 구현하기 위한 인터페이스
  • ArrayList, Vector, LinkedLis 등이 많이 사용 됨

▶ ArrayList와 Vector 클래스

  • 객체 배열을 구현한 클래스
  • Vector는 자바2부터 제공된 클래스
  • 멀티 쓰레드 상태에서 리소스에 대한 동기화가 필요한 경우 Vector를 사용
  • 일반적으로 ArrayList를 더 많이 사용함
  • ArrayList에 동기화 기능이 추가되어야 하는 경우
Collections.synchronizedList(new ArrayList<String>());
  • 동가회(synchronization): 두 개의 쓰레드가 동시에 하나의 리소스에 접근할 때 순서를 맞추어서 데이터에 오류가 발생하지 않도록 함

▶ LinkedList 클래스

  • 논리적으로 순차적인 자료구조가 구현된 클래스
  • 다음 요소에 대한 참조값을 가지고 있음
  • 요소의 추가/삭제에 드는 비용이 배열보다 적음
  • 추가하기
  • 삭제하기

Member.java

package collection;

public class Member {

	private int memberId;
	private String memberName;

	public Member(int memberId, String memberName) {
		this.memberId = memberId;
		this.memberName = memberName;
	}
	
	public int getMemberId() {
		return memberId;
	}
	public void setMemberId(int memberId) {
		this.memberId = memberId;
	}
	public String getMemberName() {
		return memberName;
	}
	public void setMemberName(String memberName) {
		this.memberName = memberName;
	}
	
	public String toString() {
		return memberName + "회원님의 아이디는 " + memberId + "입니다.";
	}
	
}

MemberArrayList.java

package collection.arraylist;

import java.util.ArrayList;
import collection.Member;

public class MemberArrayList {

	private ArrayList<Member> arrayList;

	public MemberArrayList() {
		arrayList = new ArrayList<Member>();
	}
	
	public void addMember(Member member) {
		arrayList.add(member);
	}
	
	public boolean removeMember(int memberId) {
		
		for(int i = 0; i < arrayList.size(); i++) {
			Member member = arrayList.get(i);
			int tempId = member.getMemberId();
			if(memberId == tempId) {
				arrayList.remove(i);
				return true;
			}
		}
		
		System.out.println(memberId + "가 존재하지 않습니다.");
		return false;
		
	}
	
	public void showAll() {
		
		for(Member member : arrayList) {
			System.out.println(member);
		}
		System.out.println();
//		System.out.println(arrayList);
	}
}

MemberArrayListTest.java

package collection.arraylist;

import collection.Member;

public class MemberArrayListTest {

	public static void main(String[] args) {

		MemberArrayList memberArrayList = new MemberArrayList();
		
		Member memberLee = new Member(101, "이순신");
		Member memberKim = new Member(102, "김유신");
		Member memberShin = new Member(103, "신사임당");
		
		memberArrayList.addMember(memberLee);
		memberArrayList.addMember(memberKim);
		memberArrayList.addMember(memberShin);
		memberArrayList.showAll();
		
		memberArrayList.removeMember(memberKim.getMemberId());
		memberArrayList.showAll();
	}

}

실행 결과

이순신회원님의 아이디는 101입니다.
김유신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.

이순신회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.

▶ Stack과 Queue

  • Stack과 Queue의 기능은 구현된 클래스가 있지만 ArrayList나 LinkedList를 활용하여서 사용할 수도 있음

  • Stack: Last In First Out (LIFO)
    맨 마지막에 추가된 요소가 먼저 꺼내지는 자료구조
    게임의 무르기 기능, 최근 자료 추출 등에서 사용

  • Queue: First In First Out (FIFO)

  • 먼저 저장된 자료가 먼저 꺼내지는 선착순, 대기열 구조

StackTest.java

package collection.arraylist;

import java.util.ArrayList;

class MyStack{
	
	private ArrayList<String> arrayStack = new ArrayList<String>();
	
	public void push(String data) {
		arrayStack.add(data);
	}
	
	public String pop() {
		
		int len = arrayStack.size();
		if(len == 0) {
			System.out.println("스택이 비었습니다.");
			return null;
		}
		
		return arrayStack.remove(arrayStack.size() - 1);
				
	}
	
	public String peek() {
		
		int len = arrayStack.size();
		if(len == 0) {
			System.out.println("스택이 비었습니다.");
			return null;
		}
		
		return arrayStack.get(arrayStack.size()  - 1);
	
	}
}

public class StackTest {

	public static void main(String[] args) {

		MyStack stack = new MyStack();
		
		stack.push("a");
		stack.push("b");
		stack.push("c");
		
		System.out.println(stack.peek());
		System.out.println(stack.peek());
	
		System.out.println(stack.pop());
		System.out.println(stack.pop());	
		System.out.println(stack.pop());
		System.out.println(stack.pop());
	}

}

실행 결과

c
c
c
b
a
스택이 비었습니다.
null

QueueTest.java

package collection.arraylist;

import java.util.ArrayList;

class MyQueue {
	
	private ArrayList<String> arrayQueue = new ArrayList<String>();
	
	public void enQueue(String data) {
		arrayQueue.add(data);
	}
	
	public String deQueue() {
		int len = arrayQueue.size();
		
		if(len == 0) {
			System.out.println("큐가 비었습니다.");
			return null;
		}
		
		return arrayQueue.remove(0);
	}
}

public class QueueTest {

	public static void main(String[] args) {

		
	}

}

✔ Iterator 사용하여 순회하기

  • get(i) 안될 때, hash를 사용해서 i번째 가져오지 못할 때
  • Collection의 개체를 순회하는 인터페이스
  • iterator() 메서드 호출
Iterator ir = memberArrayList.iterator();
  • 선언된 메서드
메서드설명
boolean hashNext()이후에 요소가 더 있는지를 체크하는 메서드이며, 요소가 있다면 true를 반환합니다.
E next()다음에 있는 요소를 반환합니다.

[Iterator로 ArrayList의 removeMember() 다시 작성해보기]

public boolean removeMember(int memberId) {
		
//		for(int i = 0; i < arrayList.size(); i++) {
//			Member member = arrayList.get(i);
//			int tempId = member.getMemberId();
//			if(memberId == tempId) {
//				arrayList.remove(i);
//				return true;
//			}
//		}

		Iterator<Member> iterator = arrayList.iterator();
		while(iterator.hasNext()) {
			Member member = iterator.next();
			
			int tempId = member.getMemberId();
			if(memberId == tempId) {
				arrayList.remove(member);
				return true;
			}
		}
		
		System.out.println(memberId + "가 존재하지 않습니다.");
		return false;
		
	}
	

✔ Set 인터페이스

  • Collection 하위의 인터페이스
  • 중복을 허용하지 않음
  • 아이디, 주민번호, 사번 등 유일한 값이나 객체를 관리할 때 사용
  • List는 순서 기반의 인터페이스이지만, Set은 순서가 없음
  • 저장된 순서와 출력순서는 다를 수 있음 (hash방식으로 저장)
  • get(i)메서드가 제공되지 않음

▶ HashSet 클래스

HashSetTest.java

package collection.hashset;

import java.util.HashSet;

public class HashSetTest {

	public static void main(String[] args) {
		
		HashSet<String> set = new HashSet<String>();
		
		boolean b1 = set.add("aaa");
		
		System.out.println(b1);
		set.add("bbb");
		set.add("ccc");
		
		System.out.println(set); // 들어가는 순서 저장되는 순서 동일하지 않다.
		
		boolean b = set.add("aaa");
		System.out.println(b); // 같은 값이라 안들어감 --> false
		
		System.out.println(set);

	}

}

실행 결과

true
[aaa, ccc, bbb]
false
[aaa, ccc, bbb]

MemberHashSet.java

package collection.hashset;

import java.util.HashSet;
import java.util.Iterator;

import collection.Member;

public class MemberHashSet {

	private HashSet<Member> hashSet;

	public MemberHashSet() {
		hashSet = new HashSet<Member>();
	}
	
	public void addMember(Member member) {
		hashSet.add(member);
	}
	
	public boolean removeMember(int memberId) {
		
		Iterator<Member> iterator = hashSet.iterator();
		while(iterator.hasNext()) {
			Member member = iterator.next();
			
			int tempId = member.getMemberId();
			if(memberId == tempId) {
				hashSet.remove(member);
				return true;
			}
		}
		
		System.out.println(memberId + "가 존재하지 않습니다.");
		return false;
		
	}
	
	public void showAll() {
		
		for(Member member : hashSet) {
			System.out.println(member);
		}
		System.out.println();
//		System.out.println(arrayList);
	}

}

MemberHashSetTest.java

package collection.hashset;

import collection.Member;

public class MemberHashSetTest {

	public static void main(String[] args) {

		MemberHashSet memberHashSet = new MemberHashSet();
		
		Member memberLee = new Member(101, "이순신");
		Member memberKim = new Member(102, "김유신");
		Member memberShin = new Member(103, "신사임당");
		
		memberHashSet.addMember(memberLee);
		memberHashSet.addMember(memberKim);
		memberHashSet.addMember(memberShin);
		
		memberHashSet.showAll();
		
		Member memberLee2 = new Member(101, "이몽룡");
		memberHashSet.addMember(memberLee2);
		memberHashSet.showAll(); 
		// 같은 아이디에 add 되면 안됨. But 왜 작동했을까?
		// Member클래스에 equals(), hashCode()를 구현해야 HashSet에서 add할 때 기존 멤버 같은지 여부 체크할 수 있음.
		
	}

}

실행 결과

김유신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.
이순신회원님의 아이디는 101입니다.

김유신회원님의 아이디는 102입니다.
이몽룡회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.
이순신회원님의 아이디는 101입니다.

[Member클래스의 hashCode(), equals() 오버라이딩하기]
Member.java

package collection;

public class Member {

	...
	
    @Override
	public int hashCode() {
		return memberId;
	}

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Member) {
			Member member = (Member) obj;
			
			if(this.memberId == member.memberId) {
				return true;
			}
			else return false;
		}
		return false;
	}
	
}

MemberHashSetTest.java 실행 결과

이순신회원님의 아이디는 101입니다.
김유신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.

이순신회원님의 아이디는 101입니다.
김유신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.

▶ TreeSet 클래스

  • 객체의 정렬에 사용되는 클래스
  • 중복을 허용하지 않으면서 오름차순이나 내림차순으로 객체를 정렬함
  • 내부적으로 이진 검색 트리(binary search tree)로 구현되어 있음
  • 이진 검색 트리에 자료가 저장될 때 비교하여 저장될 위치를 정함
  • 객체 비교를 위해 Comparable이나 Comparator 인터페이스를 구현해야 함 (둘 중 하나 구현하기, 주로 Comparable 많이 사용)

▶ Comparable 인터페이스와 Comparator 인터페이스

  • 정렬 대상이 되는 클래스가 구현해야 하는 인터페이스
  • Comparable은 compareTo() 메서드를 구현
    매개 변수와 객체 자신(this)을 비교
  • Comparator는 compare()메서드를 구현
    두 개의 메개 변수를 비교
    TreeSet 생성자에 Comparator가 구현된 객체를 매개변수로 전달
TreeSet<Member> treeSet = new TreeSet<Member>(new Member());
  • 일반적으로 Comparable을 더 많이 사용
  • 이미 Comparable이 구현된 경우 Comparator를 이용하여 다른 정렬 방식을 정의할 수 있음

MemberTreeSet.java

package collection.treeset;

import java.util.Iterator;
import java.util.TreeSet;

import collection.Member;

public class MemberTreeSet {

	private TreeSet<Member> treeSet;

	public MemberTreeSet() {
		treeSet = new TreeSet<Member>();
		//treeSet = new TreeSet<Member>(new Member());
		//compare 사용할 땐 생성자에 default constructor 불러줘야함
	}
	
	public void addMember(Member member) {
		treeSet.add(member);
	}
	
	public boolean removeMember(int memberId) {
		
		Iterator<Member> iterator = treeSet.iterator();
		while(iterator.hasNext()) {
			Member member = iterator.next();
			
			int tempId = member.getMemberId();
			if(memberId == tempId) {
				treeSet.remove(member);
				return true;
			}
		}
		
		System.out.println(memberId + "가 존재하지 않습니다.");
		return false;
		
	}
	
	public void showAll() {
		
		for(Member member : treeSet) {
			System.out.println(member);
		}
		System.out.println();
	}

}

MemberTreeSetTest.java

package collection.treeset;

import collection.Member;

public class MemberTreeSetTest{

	public static void main(String[] args) {

		MemberTreeSet memberHashSet = new MemberTreeSet();
		
		Member memberLee = new Member(102, "이순신");
		Member memberKim = new Member(101, "김유신");
		Member memberShin = new Member(103, "신사임당");
		
		memberHashSet.addMember(memberLee);
		memberHashSet.addMember(memberKim);
		memberHashSet.addMember(memberShin);
		
		memberHashSet.showAll();
		
		// 어떻게 비교해서 트리 구성할지 정해지지 않아 오류 발생-->Member클래스 오버라이딩하기
		
	}

}

Member.java

package collection;

import java.util.Comparator;

public class Member implements Comparable<Member>, Comparator<Member> {

	private int memberId;
	private String memberName;
	
	public Member() {}

	public Member(int memberId, String memberName) {
		this.memberId = memberId;
		this.memberName = memberName;
	}
	
	public int getMemberId() {
		return memberId;
	}
	public void setMemberId(int memberId) {
		this.memberId = memberId;
	}
	public String getMemberName() {
		return memberName;
	}
	public void setMemberName(String memberName) {
		this.memberName = memberName;
	}
	
	public String toString() {
		return memberName + "회원님의 아이디는 " + memberId + "입니다.";
	}

	@Override
	public int hashCode() {
		return memberId;
	}

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Member) {
			Member member = (Member) obj;
			
			if(this.memberId == member.memberId) {
				return true;
			}
			else return false;
		}
		return false;
	}
	
	/*** Comparable, Comparator 구현 ***/

	@Override
	public int compareTo(Member member) {
		// id 기준으로
		// 더 큰 경우에 양수 반환 됨 --> 오름차순 정렬됨(음수 --> 내림차순)
//		return (this.memberId - member.memberId);
		
		// name 기준으로(오름차순) (-1 곱하면 내림차순)
		return (this.memberName.compareTo(member.memberName));
	}

	@Override
	public int compare(Member member1, Member member2) {
		return member1.memberId - member2.memberId;
	}
	
}

실행 결과

김유신회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.
이순신회원님의 아이디는 102입니다.

ComparatorTest.java

package collection.treeset;

import java.util.Comparator;
import java.util.TreeSet;

class MyCompare implements Comparator<String>{

	@Override
	public int compare(String str1, String str2) {
		// 내림차순
		return str1.compareTo(str2) * (-1);
	}
	
}

public class ComparatorTest {
	
	public static void main(String[] args) {
		
		TreeSet<String> tree = new TreeSet<String>(new MyCompare());
		
		tree.add("aaa");
		tree.add("ccc");
		tree.add("bbb");
		
		System.out.println(tree);
	}

}

실행 결과

[ccc, bbb, aaa]

◼ Map 인터페이스

  • key-value pair의 객체를 관리하는데 필요한 메서드가 정의됨
  • key는 중복될 수 없음
  • 검색을 위한 자료구조
  • key를 이용하여 값을 저장하거나 검색, 삭제할 때 사용하면 편리함
  • 내부적으로 hash 방식으로 구현됨
index = hash(key) // index는 저장 위치
  • key가 되는 객체는 객체의 유일성함의 여부를 알기 위해 equals()와 hashCode()메서드를 재정의함
  • 여러 클래스들이 Map 인터페이스를 구현함
  • Map 인터페이스에 선언된 주요 메서드
메서드설명
V put(K key, V valuekey에 해당하는 value 값을 map에 넣습니다.
V get(K key)key에 해당하는 value 값을 반환합니다.
boolean isEmpty()Map이 비었는지 여부를 반환합니다.
boolean containsKey(Object key)Map에 해당 key가 있는지 여부를 반환합니다.
boolean containsValue(Object value)Map에 해당 value가 있는지 여부를 반환합니다.
Set keyset()key 집합을 Set로 반환합니다. (중복 안 되므로 Set)
Collection values()value를 Collection으로 반환합니다. (중복 무관)
V remove(key)key가 있는 경우 삭제합니다.
boolean remove(Object key, Object value)key가 있는 경우 key에 해당하는 value가 매개변수와 일치할 때 삭제합니다.

✔ HashMap 클래스

  • Map 인터페이스를 구현한 클래스 중 가장 일반적으로 사용하는 클래스
  • HashTable 클래스는 자바2부터 제공된 클래스로 Vector처럼 동기화를 제공함
  • 여러 메서드를 활용하여 pair 자료를 쉽고 빠르게 관리할 수 있음

[HashMap 클래스 사용 예]

  • 객체 추가하고 검색하여 삭제하기
  • 객체 순회하기
  • iterator() 메서드는 하나의 Collection 객체만을 반환하므로 pair로 이루어진 객체는 각각 순회해야 함

MemberHashMap.java

package collection.hashmap;

import java.util.HashMap;
import java.util.Iterator;

import collection.Member;

public class MemberHashMap {

	private HashMap<Integer, Member> hashMap;

	public MemberHashMap() {
		hashMap = new HashMap<Integer, Member>();
	}
	
	public void addMember(Member member) {
		hashMap.put(member.getMemberId(), member);
	}
	
	public boolean removeMember(int memberId) {
		if(hashMap.containsKey(memberId)) {
			hashMap.remove(memberId);
			return true;
		}
		
		System.out.println(memberId + "가 존재하지 않습니다.");
		return false;
	}
	
	public void showAllMember() {
		Iterator<Integer> ir = hashMap.keySet().iterator();
		
		while(ir.hasNext()) {
			int key = ir.next();
			
			Member member = hashMap.get(key);
			System.out.println(member);
		}
	}
	
}

MemberHashMapTest.java

package collection.hashmap;

import collection.Member;
import collection.treeset.MemberTreeSet;

public class MemberHashMapTest {

	public static void main(String[] args) {
		MemberHashMap memberHashMap = new MemberHashMap();
		
		Member memberLee = new Member(102, "이순신");
		Member memberKim = new Member(101, "김유신");
		Member memberShin = new Member(103, "신사임당");
		
		memberHashMap.addMember(memberLee);
		memberHashMap.addMember(memberKim);
		memberHashMap.addMember(memberShin);
		
		memberHashMap.showAllMember();
		
		System.out.println();
		
		memberHashMap.removeMember(102);
		memberHashMap.showAllMember();
		
		
	}

}

실행 결과

김유신회원님의 아이디는 101입니다.
이순신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.

김유신회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.

✔ TreeMap 클래스

  • key 객체를 정렬하여 key-value를 pair로 관리하는 클래스
  • key에 사용되는 클래스에 Comparable, Comparator 인터페이스를 구현
  • java에 많은 클래스들은 이미 Comparale이 구현되어 있음
  • 구현 된 클래스를 key로 사용하는 경우는 구현할 필요 없음

MemberTreeMap.java

package collection.treemap;

import java.util.Iterator;
import java.util.TreeMap;

import collection.Member;

public class MemberTreeMap {

	private TreeMap<Integer, Member> treeMap;

	public MemberTreeMap() {
		treeMap = new TreeMap<Integer, Member>();
	}
	
	public void addMember(Member member) {
		treeMap.put(member.getMemberId(), member);
	}
	
	public boolean removeMember(int memberId) {
		if(treeMap.containsKey(memberId)) {
			treeMap.remove(memberId);
			return true;
		}
		
		System.out.println(memberId + "가 존재하지 않습니다.");
		return false;
	}
	
	public void showAllMember() {
		Iterator<Integer> ir = treeMap.keySet().iterator();
		
		while(ir.hasNext()) {
			int key = ir.next();
			
			Member member = treeMap.get(key);
			System.out.println(member);
		}
	}
	
}

MemberTreeMapTest.java

package collection.treemap;

import collection.Member;
import collection.treeset.MemberTreeSet;

public class MemberTreeMapTest {

	public static void main(String[] args) {
		MemberTreeMap memberTreeMap = new MemberTreeMap();
		
		Member memberLee = new Member(102, "이순신");
		Member memberKim = new Member(101, "김유신");
		Member memberShin = new Member(103, "신사임당");
		
		memberTreeMap.addMember(memberLee);
		memberTreeMap.addMember(memberKim);
		memberTreeMap.addMember(memberShin);
		
		memberTreeMap.showAllMember(); // 정렬되어 출력 됨
		
		System.out.println();
		
		memberTreeMap.removeMember(102);
		memberTreeMap.showAllMember();
		
		
	}

}

실행 결과`

김유신회원님의 아이디는 101입니다.
이순신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.

김유신회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.

0개의 댓글