210723 금
컬렉션(Collection) 프레임 워크
1. 컬렉션 프레임 워크
: 자료구조를 사용해서 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 자바에서 제공하는 인터페이스와 구현 클래스 패키지의 총칭
-추가, 삭제, 정렬 등의 기능처리가 간단하게 해결 되어 자료구조적 알고리즘을 구현할 필요 없음
-java.util 패키지에 포함되며, 인터페이스를 통해 정형화된 방법으로 다양한 컬렉션 클래스 이용 가능
*컬렉션
: 객체의 저장
*프레임 워크
: 사용 방법을 정해놓은 라이브러리
<자료구조>
1) 배열의 문제점
(1) 한 번 크기를 지정하면 변경할 수 없다.
- 공간 크기가 부족하면 에러가 발생 => 할당 시 넉넉한 크기로 할당하게 됨 (메모리 낭비)
- 필요에 따라 공간을 늘리거나 줄일 수 없음
(2) 배열에 기록된 데이터에 대한 중간 위치의 추가, 삭제가 불편하다.
- 추가, 삭제할 데이터부터 마지막 기록된 데이터까지 하나씩 뒤로 밀어내고 추가해야 함 (복잡한 알고리즘)
(3) 한 타입의 데이터만 저장 가능하다
2) 컬렉션의 장점
(1) 저장하는 크기의 제약이 없다.
(2) 추가, 삭제, 정렬 등의 기능 처리가 간단하게 해결된다.
- 자료를 구조적으로 처리 하는 자료구조가 내장되어 있어 알고리즘 구현이 필요 없음
(3) 여러 타입의 데이터가 저장 가능하다.
- 객체만 저장할 수 있기 때문에 필요에 따라 기본 자료형을 저장해야 하는 경우 Wrapper클래스 사용
3) 컬렉션의 주요 인터페이스
-List와 Set은 반대되는 개념이다
(1) List 컬렉션
1> 특징
배열과 비슷하게 객체를 인덱스로 관리한다.
2> 장점
-배열과 달리 저장 용량이 자동으로 증가하며, 객체를 저장할 때 자동 인덱스가 부여 된다.
-추가, 삭제, 검색을 위한 다양한 메소드들이 제공된다.
-객체 자체를 저장하는 것이 아니라 객체의 번지를 참조하기 때문에 동일한 객체를 중복 저장할 수 있다(0번 인덱스의 객체, 1번의 인덱스의 객체를 다르게 취급한다)
-null도 저장이 가능하다(이 경우 해당 인덱스는 객체를 참조하지 않는다)
3> 구현 클래스
-ArrayList, Vector, LinkedList 등
*인덱스로 객체를 관리하기 때문에 인덱스를 매개값으로 갖는다
<1> ArrayList
-List의 후손으로 초기 저장 용량은 10으로 자동 설정되며 따로 지정도 가능
-저장 용량을 초과한 객체들이 들어오면 자동으로 늘어나며 고정도 가능
-동기화(Synchronized)를 제공하지 않음
-ArrayList와 Vector는 거의 비슷하다
package com.kh.chap01_list.part01_basic.controller;
import java.util.ArrayList;
import com.kh.chap01_list.part01_basic.model.vo.Student;
public class ArrayListTest {
// 컬렉션 타입을 사용하는 경우
private ArrayList list = new ArrayList();
//학생 추가
public void addStudent(Student std) {
list.add(std);
}
//학생 출력
public void printStudent() {
for(int i = 0 ; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
//학생 삭제
public void removeStudent(int index) {
list.remove(index);
}
}
package com.kh.chap01_list.part01_basic.controller;
import com.kh.chap01_list.part01_basic.model.vo.Student;
public class ObjectArrayTest {
//객체 배열을 사용하는 경우
private Student[] arr = new Student[3];
private int size = 0 ; //객체 배열의 인덱스 및 현재 저장 된 요소 관리용 변수
//학생 추가 메소드
public void addStudent(Student std) {
if(size < arr.length) {
arr[size++] = std;
}else {
// 기존 배열의 크기를 넘어서는 경우에 대한 알고리즘을 직접 구현해야 함
Student[] newArr = new Student[arr.length + 10];
System.arraycopy(arr, 0, newArr, 0, arr.length);
newArr[size++] = std;
arr = newArr;
}
}
//학생 출력 메소드
public void printStudent() {
for(int i = 0 ; i < size ; i++) {
System.out.println(arr[i]);
}
}
//학생 삭제 메소드
public void removeStudent(int index) {
for(int i = index; i < arr.length - 1 ; i++) {
// 해당 인덱스는 지워주고 뒤의 값을 앞으로 당겨주는 알고리즘을 직접 구현해야 함
arr[i] = arr[i+1];
}
size--;
}
//특정 인덱스에 학생 삽입하고 싶다면?
// => 해당 인덱스부터 값을 뒤로 밀어주는 알고리즘을 구현해야 하며
// 만약 배열의 길이가 부족하다면 그 이전에 배열 크기도 늘려줘야 한다
}
package com.kh.chap01_list.part01_basic.model.vo;
public class Student {
private String name;
private int score;
public Student() {}
public Student(String name, int score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
public void setName(String name) {
this.name = name;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", score=" + score + "]";
}
}
package com.kh.chap01_list.part01_basic.run;
import com.kh.chap01_list.part01_basic.controller.ArrayListTest;
import com.kh.chap01_list.part01_basic.controller.ObjectArrayTest;
import com.kh.chap01_list.part01_basic.model.vo.Student;
public class Run {
public static void main(String[] args) {
//ObjectArrayTest test = new ObjectArrayTest();
ArrayListTest test = new ArrayListTest();
System.out.println("학생 3명 추가");
test.addStudent(new Student("정한", 90));
test.addStudent(new Student("부승관", 100));
test.addStudent(new Student("금성무", 60));
System.out.println("현재 등록 된 학생 출력");
test.printStudent();
System.out.println("학생 1명 더 추가");
test.addStudent(new Student("신사임당", 90));
test.printStudent();
//"main" java.lang.ArrayIndexOutOfBoundsException: 3 => 이 오류 발생
/*
* 학생 3명 추가
현재 등록 된 학생 출력
Student [name=정한, score=90]
Student [name=부승관, score=100]
Student [name=금성무, score=60]
학생 1명 더 추가
Student [name=정한, score=90]
Student [name=부승관, score=100]
Student [name=금성무, score=60]
Student [name=신사임당, score=90]
*/
System.out.println("현재 등록 된 학생 출력");
test.printStudent();
System.out.println("1번 인덱스 학생 제거");
test.removeStudent(1);
System.out.println("현재 등록된 학생 출력");
test.printStudent();
}
}
<2> Vector
-구버전 st(Array와 비교 시)
-List의 후손
-ArrayList와 동등하지만 동기화(Synchronized)를 제공한다는 점이 ArrayList와 차이점
-List 객체들 중에서 가장 성능이 좋지 않음
-동기화를 하기 때문에 성능이 조금 더 떨어진다
<3> LinkedList
1] 특징
-List의 후손으로 인접 참조를 링크해 체인처럼 관리
-객체끼리 서로 참조하고 있음(주소값을 가지고 있다는 뜻)
2] 장점
-특정 인덱스에서 객체를 제거하거나 추가하게 되면 바로 앞/뒤 링크만 변경하면 되기 때문에 객체 삭제와 삽입이 빈번하게 일어나는 곳에서는 ArrayList보다 성능이 좋음
-기본 사용에서는 ArrayList가 더 효율적이나 객체의 추가와 제거가 빈번하게 일어나는 상황에서는 LinkedList가 성능이 더 좋다
package com.kh.chap01_list.part02_list.controller;
import java.util.ArrayList;
import java.util.List;
import com.kh.chap01_list.part02_list.model.vo.Music;
public class ListController {
/*
* List계열의 특징 : 순서 유지, 중복 저장 가능
* List 계열의 종류 : ArrayList(동기화X), Vector(동기화O), LinkedList
* LinkedList는 객체 삽입, 삭제가 빈번하게 이뤄지는 경우 ArrayList보다 효율이 좋음
* Vector는 ArrayList의 구버전이며 리스트 계열의 사용 메소드는 동일하므로 ArrayList를 대표로 테스트
*/
public void doList() {
//List는 인터페이스이므로 객체 생성이 불가능하다
//List list = new List();
//List의 후손 클래스로 객체 생성(다형성 : 부모 레퍼런스로 자식 객체를 다룸)
//List list = new ArrayList();
//Q. 노란줄(경고성 메세지)가 많이 뜨는 이유?
//A. 어떤 타입을 지정하는지 규정하지 않아서 안정성에 문제가 있다고 알려주는 메세지
//ArrayList<Music> list = new ArrayList<Music>(3);에서
//<Music>을 추가해 줌
//제네릭을 <Music>으로 지정해주면 노란줄을 사라지고 String 타입은 저장 불가능하게 됨
//Q. 제네릭을 선언하는 이유(장점)
//A. 1) 안정성(다른 타입 추가 시 컴파일 에러 발생)
//2) 반환형 다운 캐스팅 불필요
ArrayList<Music> list = new ArrayList<Music>(3);
// 크기 지정 가능. 지정하지 않으면 기본이 10개
//1. add(E e) : 리스트의 끝에 인스턴스 데이터 추가
//E => Element 요소라는 뜻으로 실제 컬렉션에 담기는 타입을 말한다
list.add(new Music("부승관", "거침없이"));
list.add(new Music("부승관", "wi-fi"));
list.add(new Music("세븐틴", "박수"));
//list.add("끝");
System.out.println(list);
//1. 크기의 제한이 없음(초기 크기 3에서 자동으로 증가)
//2. 여러 타입의 객체를 저장 가능(Music 객체가 아닌 String 객체도 담김)
//[Music [artist=부승관, title=거침없이],
//Music [artist=부승관, title=wi-fi], Music [artist=세븐틴, title=박수], 끝]
//2. add(int index, E e) : 인덱스 지정하여 해당 인덱스에 인스턴스 추가
list.add(1, new Music("앤마리", "2002"));
System.out.println(list);
//[Music [artist=부승관, title=거침없이], Music [artist=앤마리, title=2002],
//Music [artist=부승관, title=wi-fi], Music [artist=세븐틴, title=박수], 끝]
// => 중간에 삽입한 것
//3. set(int index, E e) : 지정한 인덱스의 값을 전달한 인스턴스로 변경
list.set(2, new Music("혁오", "첨밀밀"));
System.out.println(list);
//[Music [artist=부승관, title=거침없이], Music [artist=앤마리, title=2002],
//Music [artist=혁오, title=첨밀밀], Music [artist=세븐틴, title=박수], 끝]
//4. size() : 리스트 안에 몇 개의 데이터가 들어 있는지 확인
System.out.println(list.size());
//5. remove(int index) : 해당 인덱스의 인스턴스 삭제
list.remove(1);
System.out.println(list);
//[Music [artist=부승관, title=거침없이], Music [artist=혁오, title=첨밀밀],
//Music [artist=세븐틴, title=박수], 끝]
//6. get(int index) : 해당 인덱스의 인스턴스 조회
//Music m = (Music)list.get(0); //다운 캐스팅(부모 => 자식)은 명시화
//뮤직 객체 지정 후에는 다운캐스팅 불필요
Music m = list.get(0);
System.out.println(m);
//Music [artist=부승관, title=거침없이]
//7. contains(Object o) : 포함하고 있는지 참 거짓 리턴
boolean bool = list.contains(new Music("혁오", "첨밀밀"));
System.out.println(bool);
//Music 클래스에 equals 메소드가 오버라이딩 되어 있지 않아서
//contains 메소드 내부에서 필드 값 비교를 위해 equals를 호출했을 시
//Object 클래스의 equals 메소드가 호출 되어 주소 값 비교를 하고 있어 false
//=> Music 클래스에 필드값 비교를 하는 equals 메소드를 오버라이딩 하자!
//8. indexOf(Object o) : 해당 값을 가진 인덱스 리턴
int index = list.indexOf(new Music("혁오", "첨밀밀"));
System.out.println(index);
//답 : 1
//9. subList(int index1, int index2) : index1부터 index2 이전까지 List로 추출하여 리턴
List<Music> sub = list.subList(0, 2);
System.out.println(sub);
//[Music [artist=부승관, title=거침없이], Music [artist=혁오, title=첨밀밀]]
//10. addAll(Collection c) : 리스트의 끝에 컬렉션 추가
list.addAll(sub);
System.out.println(list);
//[Music [artist=부승관, title=거침없이], Music [artist=혁오, title=첨밀밀],
//Music [artist=세븐틴, title=박수], 끝,
//Music [artist=부승관, title=거침없이], Music [artist=혁오, title=첨밀밀]]
//11. isEmpty() : 리스트 안의 값이 비었는지 참 거짓 리턴
System.out.println(list.isEmpty());
//false
//12. clear() : 전체 삭제
list.clear();
System.out.println(list.isEmpty());
//true
}
}
package com.kh.chap01_list.part02_list.model.vo;
public class Music {
private String artist;
private String title;
public Music() {}
public Music(String artist, String title) {
super();
this.artist = artist;
this.title = title;
}
public String getArtist() {
return artist;
}
public String getTitle() {
return title;
}
public void setArtist(String artist) {
this.artist = artist;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String toString() {
return "Music [artist=" + artist + ", title=" + title + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((artist == null) ? 0 : artist.hashCode());
result = prime * result + ((title == null) ? 0 : title.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Music other = (Music) obj;
if (artist == null) {
if (other.artist != null)
return false;
} else if (!artist.equals(other.artist))
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
}
package com.kh.chap01_list.part02_list.run;
import com.kh.chap01_list.part02_list.controller.ListController;
public class Run {
public static void main(String[] args) {
ListController lc = new ListController();
lc.doList();
}
}
(2) Set 컬렉션
-순서를 유지하지 않고 저장한다.
-중복 저장이 안된다.
-주머니 안에 공을 넣는다고 상상하라.
(3) Map 컬렉션
-키와 값을 묶어서 저장하는 특징이 있다(List와 Set은 값만 저장)
제네릭스(Generics)
1) 장점
- 컴파일 시 강한 타입 체크 가능(실행 시, 컴파일 시 에러 방지)
- 타입 변환 제거 가능
2) 제네릭스 타입과 표현식
(1) 기본
-타입을 파라미터로 가지는 클래스와 인터페이스 선언 시 클래스 또는 인터페이스 이름 뒤에 “< >” 부호를 붙이고 사이에는 타입 파라미터 위치
[표현식]
클래스명<클래스타입> 레퍼런스 = new 생성자<클래스타입>();
클래스명<클래스타입> 레퍼런스 = new 생성자<>(); // JDK 1.7 부터 적용, 타입 추론
[사용예시]
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList<>();
(2) 제네릭스가 설정된 레퍼런스를 인자로 넘기는 경우
예) ArrayList list = new ArrayList();
BookManager bm = new BookManager();
bm.printInformation(list);
//BookManager Class
public void printInformation(ArrayList list){ ….
}
*메소드 쪽에서 받아주는 매개 변수도 제네릭스가 적용되어야 한다
(3) 제네릭스가 설정된 레퍼런스를 리턴하는 경우
예) public ArrayList getInformation(){
ArrayList list = new ArrayList();
return list;
}
*메소드의 반환형에도 제네릭스가 적용되어야 한다