Burninghering's Blog
article thumbnail
Published 2022. 2. 22. 22:04
5-10.컬렉션 프레임워크 JAVA

자바에서 제공되는 자료구조 구현 클래스들 - 컬레션 프레임워크

컬렉션 프레임워크

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

Collection 인터페이스

  • 하나의 객체를 관리하기 위한 메서드가 선언된 인터페이스
  • 하위에 List와 Set 인터페이스가 있음

List 인터페이스

  • 객체를 순서에 따라 저장하고 관리하는데 필요한 메서드가 선언된 인터페이스
  • 자료구조 리스트 (배열, 연결리스트)의 구현을 위한 인터페이스
  • 중복을 허용함
  • ArrayList, Vector, LinkedList, Stack, Queue 등...

Set 인터페이스

  • 순서와 관계없이 중복을 허용하지 않고 유일한 값을 관리하는데 필요한 메서드가 선언됨
  • 아이디, 주민번호, 사번등을 관리하는데 유용 -> 검색에 유용
  • 저장된 순서와 출력되는 순서는 다를 수 있음
  • HashSet, TreeSet등...

Map 인터페이스

  • 쌍(pair)로 이루어진 객체를 관리하는데 사용하는 메서드들이 선언된 인터페이스
  • 객체는 key-value의 쌍으로 이루어짐(사전)
  • key는 중복을 허용하지 않음
  • HashTable, HashMap, Properties, TreeMap 등이 Map 인터페이스를 구현 함

 

Set 같은 경우 순회를 하려면 Iterator 인터페이스의 함수를 사용해야 한다.


순차적으로 자료를 관리하는 List 인터페이스를 구현한 클래스와 그 활용

멤버십 관리하기

  • Member 클래스를 만들고, 아이디와 이름을 멤버 변수로 선언
  • Member 클래스로 생성된 인스턴스들을 관리하는 클래스를 컬렉션 프레임워크 클래스들을 활용하여 구현한다.

ArrayList 활용하기

  • 멤버를 순차적으로 관리함
더보기

Member.java

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;
	}
	
	@Override
	public String toString(){   //toString 메소드 오버로딩
		return memberName + " 회원님의 아이디는 " + memberId + "입니다";
	}
}

MemberArrayList.java

public class MemberArrayList {

	private ArrayList<Member> arrayList;  // ArrayList 선언 

	public MemberArrayList(){
		arrayList = new ArrayList<Member>();  //멤버로 선언한 ArrayList 생성
	}
	
	public void addMember(Member member){  //ArrayList 에 멤버 추가
		arrayList.add(member);
	}
	
	public boolean removeMember(int memberId){  // 멤버 아이디를 매개변수로, 삭제 여부를 반환
		
		for(int i =0; i<arrayList.size(); i++){ // 해당 아이디를 가진 멤버를 ArrayList에서 찾음
			Member member = arrayList.get(i);
			int tempId = member.getMemberId();
			if(tempId == memberId){            // 멤버아이디가 매개변수와 일치하면 
				arrayList.remove(i);           // 해당 멤버를 삭제
				return true;                   // true 반환
			}
		}
		
		System.out.println(memberId + "가 존재하지 않습니다");  //for 가 끝날때 까지 return 이 안된경우
		return false;                   
	}
	
	public void showAllMember(){
		for(Member member : arrayList){
			System.out.println(member);
		}
		System.out.println();
	}
}

MemberArrayListTest.java

public class MemberArrayList {

	private ArrayList<Member> arrayList;  // ArrayList 선언 

	public MemberArrayList(){
		arrayList = new ArrayList<Member>();  //멤버로 선언한 ArrayList 생성
	}
	
	public void addMember(Member member){  //ArrayList 에 멤버 추가
		arrayList.add(member);
	}
	
	public boolean removeMember(int memberId){  // 멤버 아이디를 매개변수로, 삭제 여부를 반환
		
		for(int i =0; i<arrayList.size(); i++){ // 해당 아이디를 가진 멤버를 ArrayList에서 찾음
			Member member = arrayList.get(i);
			int tempId = member.getMemberId();
			if(tempId == memberId){            // 멤버아이디가 매개변수와 일치하면 
				arrayList.remove(i);           // 해당 멤버를 삭제
				return true;                   // true 반환
			}
		}
		
		System.out.println(memberId + "가 존재하지 않습니다");  //for 가 끝날때 까지 return 이 안된경우
		return false;                   
	}
	
	public void showAllMember(){
		for(Member member : arrayList){
			System.out.println(member);
		}
		System.out.println();
	}
}

Collection 요소를 순회하는 Iterator

요소의 순회란?

  • 컬렉션 프레임워크에 저장된 요소들을 하나씩 차례로 참조하는것
  • 순서가 있는 List인터페이스의 경우는 Iterator를 사용 하지 않고 get(i) 메서드를 활용할 수 있음
  • Set 인터페이스의 경우 get(i) 메서드가 제공되지 않음 -> Iterator를 활용하여 객체를 순회함

Iterator 사용하기

  • boolean hasNext() : 이후에 요소가 더 있는지를 체크하는 메서드, 요소가 있다면 true를 반환
  • E next() : 다음에 있는 요소를 반환
더보기
public boolean removeMember(int memberId){  // 멤버 아이디를 매개변수로, 삭제 여부를 반환
	
		Iterator<Member> ir = arrayList.iterator();
		while(ir.hasNext()) {
			Member member = ir.next();
			int tempId = member.getMemberId();
			if(tempId == memberId){            // 멤버아이디가 매개변수와 일치하면 
				arrayList.remove(member);           // 해당 멤버를 삭제
				return true;                   // true 반환
			}
		}
		
		System.out.println(memberId + "가 존재하지 않습니다");  //for 가 끝날때 까지 return 이 안된경우
		return false;                   
}

 

MemberArrayList.java 의 removeMember() 메서드를 Iterator를 활용하여 구현

더보기
	public boolean removeMember(int memberId) {
//		for(int i=0; i<arrayList.size();i++) {
//			Member member = arrayList.get(i);
//			
//			int tempId = member.getMemberId();
//			if (tempId==memberId) {
//				arrayList.remove(i);
//				return true;
//			}	
//		}
		
		Iterator<Member> ir = arrayList.iterator(); //<>에 아무것도 안쓰면 Object가 된다!
		//내가 이터레이션할 요소가 Member이기 때문에 <>안에 넣는다
		
		while(ir.hasNext()) { //ir에 다음이 있는가?
			
			Member member = ir.next();
			
			int tempId = member.getMemberId();
			if (tempId==memberId) {
				arrayList.remove(member); //i를 삭제하면 안되고 오브젝트를 삭제해야 한다.
				return true;
			}
		}
			System.out.println(memberId+"가 존재하지 않습니다.");
			return false;
		}

중복되지 않게 자료를 관리하는 Set 인터페이스를 구현한 클래스와 그 활용

HashSet 클래스

  • Set 인터페이스를 구현한 클래스와 멤버의 중복 여부를 체크하기 위해, 인스턴스의 동일성을 확인해야 함
  • 동일성 구현을 위해 필요에 따라 equals()와 hashCode()메서드를 재정의함
더보기
public class HashSetTest {

	public static void main(String[] args) {

		HashSet<String> hashSet = new HashSet<String>();
		hashSet.add(new String("김유신"));
		hashSet.add(new String("이순신"));
		hashSet.add(new String("홍연의"));
		hashSet.add(new String("강감찬"));
		hashSet.add(new String("강감찬"));
		
		System.out.println(hashSet); //toString이 호출된다->자기가 가진 멤버를 쭉 반환해준다.
	}
}

 

1003이 같은데도 중복이 된다??? -> 무엇이 같은지 기준을 정해주지 않아서 

hash의 "같다"는 기준값은 우리가 정해서 equals()와 hashCode()로 만들어줘야 한다!!!

 

더보기

Member.java

package ch12;

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;
	}	
	
	@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;
	}

	@Override
	public String toString(){   //toString 메소드 오버로딩
		return memberName + " 회원님의 아이디는 " + memberId + "입니다";
	}

}

MemberHashSet.java

package ch12;

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

public class MemberHashSet {
	private HashSet<Member> hashSet; //<>안에 실제로 관리할 것을 넣으면 됨
	
	public MemberHashSet() {
		hashSet=new HashSet<>();
	}
	
	public MemberHashSet(int size) {
		hashSet=new HashSet<>(size);
	}
	
	public void addMember(Member member) {
		hashSet.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 (tempId==memberId) {
//				arrayList.remove(i);
//				return true;
//			}	
//		}
		
		Iterator<Member> ir = hashSet.iterator(); //<>에 아무것도 안쓰면 Object가 된다!
		//내가 이터레이션할 요소가 Member이기 때문에 <>안에 넣는다
		
		while(ir.hasNext()) { //ir에 다음이 있는가?
			
			Member member = ir.next();
			
			int tempId = member.getMemberId();
			if (tempId==memberId) {
				hashSet.remove(member); //i를 삭제하면 안되고 오브젝트를 삭제해야 한다.
				return true;
			}
		}
			System.out.println(memberId+"가 존재하지 않습니다.");
			return false;
		}
	
	
	public void showAllMember() {
		for(Member member : hashSet) {
			System.out.println(member);
		}
		System.out.println();
	}
}

MemberHashSetTest.java

package ch12;

public class MemberHashSetTest {

	public static void main(String[] args) {
		
		MemberHashSet memberHashSet = new MemberHashSet();
		
		Member memberLee = new Member(1001,"이순신");
		Member memberKim = new Member(1002,"김유신");
		Member memberKang= new Member(1003,"강감찬");
		
		memberHashSet.addMember(memberLee);
		memberHashSet.addMember(memberKim);
		memberHashSet.addMember(memberKang);
		
		Member memberHong= new Member(1003,"홍길동");
		
		memberHashSet.addMember(memberHong);
		memberHashSet.showAllMember();		
	}
}

정렬을 위해 Comparable 또는 Comparator 인터페이스 구현하기

TreeSet 클래스 활용하기

  • 객체의 정렬에 사용하는 클래스
  • Set 인터페이스를 구현하여 중복을 허용하지 않고, 오름차순이나 내림차순으로 객체를 정렬할 수 있음
  • 내부적으로 이진검색트리(binary search tree)로 구현됨
  • 이진검색트리에 저장하기 위해 각 객체를 비교해야 함
  • 비교 대상이 되는 객체에 Comparable이나 Comparator 인터페이스를 구현 해야 TreeSet에 추가 될 수 있음
  • String, Integer등 JDK의 많은 클래스들이 이미 Comparable을 구현했음

comparable은 java.lang 패키지 안에 있고,

Comparator는 java.util 패키지 안에 있다.

 

더보기
package ch13;

import java.util.TreeSet;

public class MemberTreeSetTest {

	public static void main(String[] args) {
	
		TreeSet<String> set = new TreeSet<String>();
		
		set.add("홍길동");
		set.add("강감찬");
		set.add("이순신");
		
		System.out.println(set);
	}
}

String이 구현해 놓은 인터페이스중에 Comparable이 있기 때문에 가능

String 클래스는 이미 Comprable 인터페이스가 구현되어 있으므로 오름차순으로 정렬되어 출력됨

 

아래 코드를 실행하면 오류가 난다.

더보기
package ch13;

import java.util.TreeSet;

public class MemberTreeSetTest {

	public static void main(String[] args) {
		
		MemberTreeSet memberTreeSet = new MemberTreeSet();
		
		Member memberLee = new Member(1001,"이순신");
		Member memberKim = new Member(1002,"김유신");
		Member memberKang= new Member(1003,"강감찬");
		
		memberTreeSet.addMember(memberLee);
		memberTreeSet.addMember(memberKim);
		memberTreeSet.addMember(memberKang);
		
		memberTreeSet.showAllMember();
	}
}
Exception in thread "main" java.lang.ClassCastException: class ch13.Member cannot be cast to class java.lang.Comparable (ch13.Member is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')

Member가 비교하려고 add를 했지만, 비교하는 애를 구현해놓지 않아서 넣을 수 없다!

그러려면 Comparable이나 Comparator를 구현해야 한다.

 

1. Comparable

Member클래스가 아이디 오름차순으로 정렬되게 하기 위해 Comparable 인터페이스를 구현

더보기

Member.java

package ch13;

public class Member implements Comparable<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;
	}	
	@Override
	public String toString(){   //toString 메소드 오버로딩
		return memberName + " 회원님의 아이디는 " + memberId + "입니다";
	}

	@Override
	public int compareTo(Member member) { //들어온 아이(자신의 Id)가 트리에 자리잡을 때까지 비교할 아이들이 member로 하나씩 들어온다.
//		if (this.memberId>member.memberId) //compareTo의 반환값은 int이므로, 들어온 애가 더 클 때 
//			return 1;
//		else if(this.memberId<member.memberId) //내림차순으로 하고 싶으면 if와 elseif의 반환값을 지금과 반대로 하면 된다
//			return -1;
//		else return 0; //같을 때
		
		return (this.memberId-member.memberId); //위 코드를 간단화 한 것
//		return (this.memberId-member.memberId) * (-1); //내림차순
	}
}

 

2. Comparator

더보기

Member.java

package ch13;

import java.util.Comparator;

public class Member implements Comparator<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;
	}	
	
	@Override
	public String toString(){   //toString 메소드 오버로딩
		return memberName + " 회원님의 아이디는 " + memberId + "입니다";
	}

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

오류가 난다?!

public class MemberTreeSet {
	private TreeSet<Member> treeSet; //<>안에 실제로 관리할 것을 넣으면 됨
	
	public MemberTreeSet() {
		treeSet=new TreeSet<Member>(new Member()); //Comparator가 구현된 것을 괄호 안에 지정해줘야 한다.
	}
}

 

++Member.java에도 디폴트 생성자 만들어줘야 한다!

public class Member implements Comparator<Member>{
	
	private int memberId;        //회원 아이디
	private String memberName;   //회원 이름

	public Member() {}
    .
    .
    .

 

Comparator의 활용

이미 Comparable이 구현된 경우 Comparator로 비교하는 방식을 다시 구현할 수 있음

(String에 이미 Comparable이 구현되어 있다는 것을 활용)

더보기
package ch13;

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

class MyCompare implements Comparator<String>{ //String에는 Comparable이 구현되어 있으니깐!

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

public class MemberTreeSetTest {

	public static void main(String[] args) {
		
		TreeSet<String> set = new TreeSet<String>(new MyCompare()); //무엇으로 비교할 것인가? -> new MyCompare()
		set.add("Park");
		set.add("Kim");
		set.add("Lee");
		
		System.out.println(set);
	}
}

쌍(pair)으로 자료를 관리하는 Map 인터페이스를 구현한 클래스와 그 활용

HashMap 클래스 활용하기

  • Map 인터페이스를 구현한 클래스와 가장 많이 사용되는 Map 인터페이스 기반 클래스
  • key - value를 쌍으로 관리하는 메서드를 구현함
  • 검색을 위한 자료구조
  • key를 이용하여 값을 저장하고 key를 이용하여 값을 꺼내오는 방식 - hash 알고리즘으로 구현 됨
  • key가 되는 객체는 중복될 수 없고 객체의 유일성을 비교를 위한 equals()와 hashCode() 메서드를 구현해야 함

// Member.java 는 기존과 동일

더보기

Member.java

package ch14;

import java.util.Comparator;

public class Member implements 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;
	}	
	
	@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;
	}

	@Override
	public String toString(){   //toString 메소드 오버로딩
		return memberName + " 회원님의 아이디는 " + memberId + "입니다";
	}

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

MemberHashMap.java

package ch14;

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

public class MemberHashMap {
	private HashMap<Integer,Member> hashMap; //keyset으로 부르면 int반환, values로 부르면 Member들이 반환
	
	public MemberHashMap() {
		hashMap=new HashMap<>();
	}
	
	public void addMember(Member member) { //충돌을 완화하기 위해 로드밸런서가 어느정도 해쉬맵이 차면 뻥튀기를 시킨다
		hashMap.put(member.getMemberId(), member);
	}
	
	public boolean removeMember(int memberId) {
		
		if(hashMap.containsKey(memberId)) {
			hashMap.remove(memberId);
		}
		System.out.println("no elements");
		return false;
	}	
	
	public void showAllMember() {
		Iterator<Integer> ir=hashMap.keySet().iterator(); //Iterator를 직접 사용할 순 없고, keySet 키값을 set으로 불러와 사용
		//keySet()이 아니라 values를 사용하면 
		while(ir.hasNext()) {
			int key=ir.next();
			Member member=hashMap.get(key); //value가 쭉 꺼내지게 됨
			System.out.println(member);
			
		}
	}
}

MemberHashMapTest.java

package ch14;

import java.util.HashMap;

public class MemberHashMapTest {

	public static void main(String[] args) {
		MemberHashMap memberHashMap= new MemberHashMap();
		
		Member memberLee = new Member(1001,"이순신");
		Member memberKim = new Member(1002,"김유신");
		Member memberKang= new Member(1003,"강감찬");
		
		memberHashMap.addMember(memberLee);
		memberHashMap.addMember(memberKim);
		memberHashMap.addMember(memberKang);
		
		memberHashMap.showAllMember();	//member에 대한 toString이 호출
		
		HashMap<Integer,String> hashMap = new HashMap<Integer,String>(); //key,value pair로 나오게 하기
		hashMap.put(1001, "Kim");
		hashMap.put(1002, "Lee");
		hashMap.put(1003, "Park");
		hashMap.put(1004, "Hong");
		
		System.out.println(hashMap);
		
	}
}

 

TreeMap 클래스(TreeSet + HashMap)

  • Map 인터페이스를 구현한 클래스이고 key에 대한 정렬을 구현할 수 있음
  • key가 되는 클래스에 Comparable이나 Comparator인터페이스를 구현함으로써 key-value 쌍의 자료를 key값 기준으로 정렬하여 관리 할 수 있음(Integer나 String은 이미 구현되어있으니 괜찮지만, 다른 클래스들은 key에 대해 만들어줘야 함)
profile

Burninghering's Blog

@개발자 김혜린

안녕하세요! 반갑습니다.