# 21. Java 20일차(230912) [국비교육]

brand_mins·2023년 9월 12일

Java

목록 보기
21/47

1. 컬렉션 프레임워크

  • 자료구조: 프로그램에서 데이터를 사용할 때 효율적으로 사용하기 위한 자료구조
  • 컬렉션: 자바에서 여러 자료구조를 사용할 수 있도록 제공하는 여러 클래스

(1) ArrayList 자료구조

  • 컬렉션에서 List를 사용하는 방법은 다음과 같다.
import java.util.ArrayList;

public class JavaStart004 {

	public static void main(String[] args) {
		// 선언
		// List arrList = new ArrayList<Integer>();
		ArrayList<Integer> arrList = new ArrayList<Integer>();
	}
}
  • ArrayList의 부모가 List이기 때문에 List에 ArrayList를 넣을 수 있음.
  • "Integer" 부분은 제네릭. List 안에 Integer 자료형을 넣겠다는 뜻.
  • 제네릭을 통해서 리스트에 데이터를 담을 수 있는 방법은 객체 형태만 가능함. 즉, 기본 자료형은 Wrapper로 사용
// 컬렉션에 메소드 add를 추가하여 데이터 추가방법
arrList.add(14);
arrList.add(15);
arrList.add(22);
arrList.add(10);
arrList.add(10);
		
// 컬렉션에 메소드 get을 이용해서 해당 인덱스의 데이터 가져오기
for(int i=0; i<arrList.size(); i++) {
	System.out.println(arrList.get(i));
}
  • 리스트 4개의 데이터를 넣는 다음 리스트에 들어있는 모든 데이터를 출력하는 프로그램임.
  • add메소드를 이용해서 arrayList에 데이터를 넣을 수 있음.
  • get메소드를 이용해서 리스트에 데이터를 읽어 올 수 있음.
  • size메소드를 이용해서 list안에 몇개의 데이터가 들어있는지 확인 가능
System.out.println("remove==========================");
// remove를 이용해서 해당 데이터를 삭제 인덱스는 0부터 시작
arrList.remove(1); // 1번째 인덱스의 내용을 삭제. 14, 22, 10
arrList.remove((Integer)10); // 리스트에 들어있는 값 중 10 삭제
for(int i : arrList) {
	System.out.println(i); // 14,22,10 출력
}
  • 리스트에 들어 있는 해당 인덱스의 데이터를 삭제하고 출력하는 프로그램.
  • remove 메소드를 이용해서 매개변수 int를 넣으면 인덱스에 해당하는 데이터가 삭제
  • 같은 데이터가 여러개일시 하나만 삭제
System.out.println("정렬==============================");
// 들어 있는 데이터를 오름차순으로 정렬
Collections.sort(arrList);
// Iterator는 리스트의 데이터를 순회하면서 접근할 수 있는 객체
// arrList.iterator()를 이용해서 해당 컬렉션의 Iterator를 얻어올 수 있음.
// 해당 인스턴스를 통해 실제데이터 접근가능
// .hasNext 다음에 읽어올 데이터가 있는지 true/false 리턴
// .Next: 데이터를 읽어오고 아직 읽어오지 않은 다음 데이터에 접근할 준비
Iterator<Integer> iter = arrList.iterator();
while(iter.hasNext()) {
	System.out.println(iter.next());
}
  • 리스트에 들어있는 데이터를 Collections.sort로 정렬
  • 내용을 Iterator를 이용해서 화면에 출력
  • Iterator은 컬렉션의 모든 데이터를 출력할 때 사용.
// indexOf을 이용해서 들어있는 데이터의 인덱스를 찾는다.
int index = arrList.indexOf((Integer)14);
System.out.println(index);
int index2 = arrList.indexOf(20);
System.out.println(index2);
		
// contains 메소드를 이용해서 존재유무 확인(true/false)
System.out.println(arrList.contains(20));
  • indexOf 메소드의 매개변수로 들어있는 데이터를 넣어서 해당 데이터가 들어있는 인덱스 얻기 가능.
  • 찾지 못하면 -1 리턴
arrList.set(2, 999);
System.out.println("-----------------------");
for(Integer item:arrList) {
System.out.println(item);
}
  • set인 경우 해당 인덱스의 값을 변경
  • 왼쪽같은 경우 2번 인덱스의 값을 999로 변경
class Rect implements Comparable<Rect> {
	public double width = 100;
	public double length = 100;
	public Rect(double width, double length) {
		this.width = width;
		this.length = length;
	}
	@Override
	public String toString() {
		return "Rect [width=" + width + ", length=" + length + "]";
	}
	public int hashCode() { }
	public boolean equals(Object obj) {}
	public double area() {
		return width * length;
	}
	public int compareTo(Rect other) {}
  • 상위 코드는 Rect 클래스인데 기존에 만들었던 것과 다른 점은 Comparable의 Rect 인터페이스르 상속받아 만들어짐.
  • 인터페이스 용도: 두 Rect 클래스 인스턴스 중 어느 것이 크냐의 정의.
  • Collections.sort()를 사용해서 정렬한다면 어떤 것이 기준이 되는지 알 수 있음.
  • 이때, 인터페이스를 상속받아 compareTo 메소드를 재정의하여 정렬기준을 만들면 compareTo에 정의한대로 list안에 Rect 인스턴스 정렬
public int compareTo(Rect other) {
// 기본 오름차순으로 정렬하자.
// 1:this가 크면, 0: 같음, -1:this가 작음
// 기본 내림차순으로 정렬
// -1:this가 크면, 0: 같음, 1:this가 작음
int val = -1;
if(this.area() == other.area()) {
	val = 0;
} else if(this.area() > other.area()) {
	val = 1;
	}
	return val;
	}
}
  • 우리가 만든 Rect 같은 클래스는 Comparable 인터페이스 재정의해주어야 Collections.sort 사용 가능함.
  • Wrapper 클래스들은 기본적으로 오름차순 정렬
  • 문제가 해결된 것처럼 보이지만 아직 hashCode와 equals 재정의하지 않음.
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
// temp = Double.doubleToLongBits(length);
// result = prime * result + (int) (temp^(temp >>> 32));
// temp = Double.doubleToLongBits(width);
// result = prime * result + (int) (temp^(temp >>> 32));
temp = Double.doubleToLongBits(area()); // 대신 추가 코드
result = prime * result + (int) (temp^(temp >>> 32));
return result;	
}
public boolean equals(Object obj) {
if(this == obj) 
	return true;
if(obj == null)
	return false;
if(getClass() != obj.getClass())
	return false;
		
Rect other = (Rect) obj;
// if(Double.doubleToLongBits(length) != Double.doubleToLongBits(other.length))
// return false;
// if(Double.doubleToLongBits(width) != Double.doubleToLongBits(other.width))
// return false;
if(this.area() != other.area()) {
	return false;
}
return true;
}
  • 만약, equals와 hashCode 재정의하지 않는다면 부모인 Object에 기술되어 있는 equals와 hashCode가 실행되어 객체가 생성된 메모리 주소 기준으로 판별하여 리턴.

  • 넓이를 기준으로 변경한다면 기존 코드에 height와 width를 주석처리. 대신 추가코드를 추가하면 사각형의 넓이의 결과로 2개의 Rect 인스턴스가 같은지 다른지 비교가능.

  • 따라서, equals 메소드 비교대상값이 width, height이면 hashCode도 똑같이 변경해야 함. area()이면 hashCode도 마찬가지.

  • 우리가 만든 Rect 클래스를 가지고 삽입, 삭제, 출력함.

  • list.remove(new Rectangle(14,14)); 부분에서 종종 객체가 삭제되지 않은 일 발생. 즉, equals 재정의하지 않아 발생함.

  • list의 조작 방법은 다음과 같다.

class Rect implements Comparable<Rect> {
	public double width = 100;
	public double length = 100;
	public Rect(double width, double length) {
		this.width = width;
		this.length = length;
	}
	@Override
	public String toString() {
		return "Rect [width=" + width + ", length=" + length + "]";
	}
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		long temp;
		// temp = Double.doubleToLongBits(length);
		// result = prime * result + (int) (temp^(temp >>> 32));
		// temp = Double.doubleToLongBits(width);
		// result = prime * result + (int) (temp^(temp >>> 32));
		temp = Double.doubleToLongBits(area()); // 대신 추가 코드
		result = prime * result + (int) (temp^(temp >>> 32));
		return result;	
	}
	
	public boolean equals(Object obj) {
		if(this == obj) 
			return true;
		if(obj == null)
			return false;
		if(getClass() != obj.getClass())
			return false;
		
		Rect other = (Rect) obj;
		// if(Double.doubleToLongBits(length) != Double.doubleToLongBits(other.length))
		// return false;
		// if(Double.doubleToLongBits(width) != Double.doubleToLongBits(other.width))
		// return false;
		if(this.area() != other.area()) {
			return false;
		}
		return true;
		}
	
	public double area() {
		return width * length;
	}
	public int compareTo(Rect other) {
		// 기본 오름차순으로 정렬하자.
		// 1:this가 크면, 0: 같음, -1:this가 작음
		// 기본 내림차순으로 정렬
		// -1:this가 크면, 0: 같음, 1:this가 작음
		int val = -1;
		if(this.area() == other.area()) {
			val = 0;
		} else if(this.area() > other.area()) {
			val = 1;
		}
		return val;
	}
}

public class JavaStart005 {

	public static void main(String[] args) {
		ArrayList<Rect> list = new ArrayList<Rect>();
		list.add(new Rect(11,11));
		list.add(new Rect(12,12));
		list.add(new Rect(14,14));
		list.add(new Rect(13,13));
		list.add(new Rect(15,16));
		list.add(new Rect(16,15));
		// list의 중간에 사각형을 추가하면 뒤로 하나씩 밀려난다.
		list.add(5, new Rect(17,17)); // 5번 위치에 사각형 추가
		Rect r = new Rect(15,15);
		list.add(r);
		
		list.remove(2); // 인덱스가 2인 데이터 삭제
		list.remove(new Rect(15,16)); // 해당 사각형 삭제
		list.remove(r); // equals 재정의하지 않아도 주소가 같아서 삭제
		
		for(Rect item:list) {
			// list 내용 확인
			System.out.println(item);
		}
		
		// 해당 사각형과 같은 사각형이 존재하는지 인덱스가 리턴
		System.out.println(list.indexOf(new Rect(13,13)));
		// 해당 사각형과 같은 사각형이 존재하는지 확인(true/false)
		System.out.println(list.contains(new Rect(13,13)));
		
		// 인덱스의 4위치에 있는 사각형을 새로운 사각형 변경
		list.set(4, new Rect(7,7));
		
		// iterator를 이용해서 list의 데이터를 순회하는 방법
		System.out.println("-------------------------------");
		Iterator<Rect> iter = list.iterator();
		while(iter.hasNext()) {
			// next 현재 데이터를 리턴하고 다음 데이터 이동
			System.out.println(iter.next());
		}
		
		// compareTo에 정의되어 있는대로 list 설정
		Collections.sort(list);
		Collections.reverse(list); // list 내용 반전
		
		System.out.println(list);
		System.out.println(list.size()); // list크기

	}

}

2. HashMap 사용하기

  • 맵은 키와 값으로 쌍을 지어 키를 통해 데이터를 저장하고 읽어오는 방식.
- 키는 String으로 객체를 사용.
- 값은 Integer 객체 사용
- 키로 값을 찾기 때문에 키값은 중복될 경우 이전 키 삭제
// 선언
HashMap<String,Integer> hashmap = new HashMap<String, Integer>();
// 삽입
hashmap.put("삼십",30);
hashmap.put("십",10); 
hashmap.put("십",100); // 기존 데이터 삭제
hashmap.put("사십",40);
hashmap.put("이십",20);
// 삭제
hashmap.remove("사십");
// 변경
hashmap.replace("이십",200);
System.out.println("------------------사십 삭제");
for(String key:hashmap.keySet()) {
	System.out.println(key);
}
// 키 배열을 이용해서 맵 출력
System.out.println(hashmap.keySet());
for(String key:hashmap.keySet()) {
	System.out.println(String.format("key:%s value:%d", key,hashmap.get(key)));
}
// iterator 이용해서 맵 출력
Iterator<String> keys = hashmap.keySet().iterator();
while(keys.hasNext()) {
	String key = keys.next();
    System.out.println(String.format("key:%s value:%d", key,hashmap.get(key)));
}
System.out.println("크기: " + hashmap.size());
}

(1) 예제

- 이전에 만든 Rect 클래스를 Rectangle 클래스로 만들어 키와 값을 사용하는 해시맵 구현
- hashmap의 키는 hash를 사용하기 때문에
- equals와 hashcode메소드를 반드시 재정의하여 재구현
- 두 사각형 객체를 짝을 지어 키와 값으로 사용한 해시맵
// 선언
HashMap<Rectangle, Rectangle> hashmap = new HashMap<Rectangle, Rectangle>();
// 삽입
hashmap.put(new Rectangle(10,11), new Rectangle(21,22));
hashmap.put(new Rectangle(11,12), new Rectangle(22,23));
hashmap.put(new Rectangle(12,13), new Rectangle(23,24));
// 삭제
hashmap.remove(new Rectangle(11,12));
// 변경하기
hashmap.replace(new Rectangle(11,12), new Rectangle(31,32));
System.out.println("--------------------11,12 삭제");
for(Rectangle key: hashmap.keySet()) {
	System.out.println(key);
}
// 키 배열을 이용한 맵출력
System.out.println(hashmap.keySet());
for(Rectangle key: hashmap.keySet()) {
System.out.println(String.format("key:%s value:%d", key, hashmap.get(key)));
}
		
// Iterator 이용한 맵출력
Iterator<Rectangle> keys = hashmap.keySet().iterator();
while(keys.hasNext()) {
	Rectangle key = keys.next();
    System.out.println(String.format("key:%s value:%d", key, hashmap.get(key)));
}
System.out.println("크기: " + hashmap.size());

3. 추가 복습

이것이 자바다 교재 예제를 참고하여 복습하였음.
- ArrayList 관련 예제
1. ArrayList를 통해 객체를 삽입하고 삭제하고 검색하는 예제
public class Board {
	private String subject = "";
	private String content = "";
	private String writer = "";
	
	public Board(String subject, String content, String writer) {
		this.subject = subject;
		this.content = content;
		this.writer = writer;
	}

	public String getSubject() {
		return subject;
	}

	public void setSubject(String subject) {
		this.subject = subject;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getWriter() {
		return writer;
	}

	public void setWriter(String writer) {
		this.writer = writer;
	}
}
import java.util.ArrayList;

public class ArrayListExample {

	public static void main(String[] args) {
		// ArrayList 컬렉션 생성
		ArrayList<Board> list = new ArrayList<Board>();
		// 객체 추가
		list.add(new Board("제목1", "내용1", "글쓴이1"));
		list.add(new Board("제목2", "내용2", "글쓴이2"));
		list.add(new Board("제목3", "내용3", "글쓴이3"));
		list.add(new Board("제목4", "내용4", "글쓴이4"));
		list.add(new Board("제목5", "내용5", "글쓴이5"));
		
		// 저장된 총 객체 수 얻기
		int size = list.size();
		System.out.println("총 객체 수: " + size);
		System.out.println();
		
		// 특정 인덱스 객체 가져오기
		Board board = list.get(2);
		System.out.println(board.getSubject() + "\t" + board.getContent() + "\t" + board.getWriter());
		System.out.println();
		
		// 모든 객체 가져오기
		for(int i=0; i<list.size(); i++) {
			Board b = list.get(i);
			System.out.println(b.getSubject() + "\t" + b.getContent() + "\t" + b.getWriter());
		}
		System.out.println();
		
		// 객체 삭제
		list.remove(2);
		// 처음 2번 인덱스의 데이터를 삭제하면 3번 인덱스가 2번 인덱스로 옮겨지는데 
		// 삭제명령어를 한번더 실행하면서 3번인덱스 값이 들어간 2번인덱스도 삭제됨.
		list.remove(2); 
		
		// 향상된 for문으로 모든 객체를 하나씩 가져오기
		for(Board b : list) {
			System.out.println(b.getSubject() + "\t" + b.getContent() + "\t" + b.getWriter());
		}		
	}
}

- HashMap 관련 예제
<정리> HashMap은 키로 사용할 객체가 hashCode() 메소드의 리턴값이 같고
equals()메소드가 true 리턴, 동일 키로 보고 중복저장x
HashMap<K(키 타입), V(값 타입)> map = new HashMap<K, V>();
1. 이름을 키로 점수를 값을 저장하는 예제
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;

public class HashMapExample {

	public static void main(String[] args) {
		// map 컬렉션 생성
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		
		// 객체 저장
		map.put("신용권", 85);
		map.put("홍길동", 90);
		map.put("김휴먼", 80);
		map.put("홍길동", 95);
		System.out.println("총 Entry 수: " + map.size());
		System.out.println();
		
		// 키로 값 얻기
		String key = "홍길동";
		// 키를 매개값으로 주면 값을 리턴
		int value = map.get(key); 
		System.out.println(key + ": " + value);
		System.out.println();
		
		// 키 Set컬렉션 얻고 반복해서 키와 값 얻기
		Set<String> keySet = map.keySet();
		Iterator<String> keyIterator = keySet.iterator();
		while(keyIterator.hasNext()) {
			String k = keyIterator.next();
			Integer v = map.get(k);
			System.out.println(k + ": " + v);
		}
		System.out.println();
		
		// 엔트리 Set컬렉션을 얻고 반복해서 키와 값 얻기
		Set<Entry<String, Integer>> entrySet = map.entrySet();
		Iterator<Entry<String,Integer>> entryIterator = entrySet.iterator();
		while(entryIterator.hasNext()) {
			Entry<String,Integer> entry = entryIterator.next();
			String k = entry.getKey();
			Integer v = entry.getValue();
			System.out.println(k + ": " + v);
		}
		System.out.println();
		
		// 키로 엔트리 삭제
		map.remove("홍길동");
		System.out.println("총 Entry 수: " + map.size());
		System.out.println();

	}

}
profile
IT 개발자가 되기 위한 기록

0개의 댓글