✍Collection (컬렉션 )
: 메모리상에서 자료를 구조적으로 처리하는 방법을 자료구조라 일컫는데
컬렉션(Collection)은 자바에서 제공하는 자료구조를 담당하는 프레임워크 == 자료구조들의 모음
java.util 패키지에 포함되며, 인터페이스를 통해 정형화된 방법으로 다양한 컬렉션 클래스 이용 가능
배열의 문제점 & 컬렉션의 장점
배열의 문제점 컬렉션의 장점(특징) 한 번 크기를 지정하면 변경할 수 없다. 저장하는 크기의 제약이 없다. 배열에 기록된 데이터에 대한 중간 위치의 추가, 삭제가 불편하다. 추가, 삭제, 정렬 등의 기능 처리가 간단하게 해결된다
- 자료를 구조적으로 처리 하는 자료구조가 내장되어 있어 알고리즘 구현이 필요 없음한 타입의 데이터만 저장 가능하다. 여러 타입의 데이터가 저장 가능하다
- 객체만 저장할 수 있기 때문에 필요에 따라 기본 자료형을 저장해야 하는 경우 Wrapper클래스 사용
1. 컬렉션의 주요 인터페이스
abstract method : 상속 받은 자식이 반드시 구현 ( 오버라이딩 강제)
-> 자식들이 모두 같은 메서드를 구현 (== 모두 동일한 이름의 기능이 있고 자식들이 비슷한 형태를 띄게 된다.)
List와 Set은 비슷한 점이 많다 == 추상화 특징을 가졌고 Map도 컬렉션에 포함된다.
똑같은 리스트여도 ArrayList와 LinkedList는 상황에 따라 맞는걸 쓰는거다
부모객체인 리스트를 참조하는 다형성의 특징을 보여준다.
🚩 List
자료들을 순차적으로 나열한 자료구조로 인덱스로 관리되며,
중복해서 객체 저장 가능 구현 클래스로 ArrayList와 Vector, LinkedList가 있음
자료들을 순차적으로 나열한 자료구조== 배열
List 계열 주요 메소드
➡ E (Element) :모든 요소 == 모든 객체
추가 - add / 수정 - set / 조회 - get / 삭제 - remove
1. ArrayList
- List의 후손 클래스
- 배열과 비슷한 형태의 리스트(가장 기본적이고 많이 사용된다.)
List의 후손으로 초기 저장 용량은 10으로 자동 설정되며 따로 지정도 가능
저장 용량을 초과한 객체들이 들어오면 자동으로 늘어나며 고정도 가능 (길이 +1) *2 한 크기로 늘어난다.
동기화(Synchronized)를 제공하지 않음
ArrayList list = new ArrayList(); // 기본 생성자로 생성 시 초기 용량 10
ArrayList stdList = new ArrayList(3); // 초기 용량 3
1) add(E e)
리스트의 맨 끝에 추가( if문 가능)
// 초기용량 3인 stdList에 값 삽입
if ( stdList.add( new Student ("홍길동", 15, 2)) ) {
System.out.println("학생 정보 추가 성공(ArrayList)");
}
if ( stdList.add( new Student ("고길동", 16, 3)) ) {
System.out.println("학생 정보 추가 성공(ArrayList)");
}
if ( stdList.add( new Student ("희동이", 8, 1)) ) {
System.out.println("학생 정보 추가 성공(ArrayList)");
}
//자동으로 ArrayList 길이가 증가하는지 확인 ==> 성공(자동으로 늘어나는 코드도 추가되어있다)
if ( stdList.add( new Student ("김영이", 17, 1)) ) {
System.out.println("학생 정보 추가 성공(ArrayList)");
}
2) toString()
리스트의 맨 끝에 추가 (if문 가능리스트에 저장된 모든 요소를 한 줄의 문자열로 반환)
System.out.println( stdList.toString() );
결과
[홍길동/15/2, 고길동/16/3, 희동이/8/1, 김영이/17/1]
3) add(int index, E e)
지정된 index에 삽입 (if사용못함)
System.out.println( stdList.toString() );
stdList.add(1, new Student("박철수", 13, 6));
System.out.println("중간 삽입 확인");
System.out.println(stdList);
결과
[홍길동/15/2, 고길동/16/3, 희동이/8/1, 김영이/17/1]
중간 삽입 확인
[홍길동/15/2, 박철수/13/6, 고길동/16/3, 희동이/8/1, 김영이/17/1]
4) size()
리스트에 저장된 데이터 개수 반환
System.out.println("저장된 학생 수 : " + stdList.size());
결과
저장된 학생 수 : 5
5) get(int index) : 리스트에 저장된 index번 째 요소 반환
리스트에 저장된 index번 째 요소 반환
System.out.println(stdList.get(0));
System.out.println(stdList.get(1));
System.out.println(stdList.get(2));
System.out.println(stdList.get(3));
System.out.println(stdList.get(4));
=> for문을 사용하기 아주 적합한 모양
결과
저장된 학생 수 : 5
홍길동/15/2
박철수/13/6
고길동/16/3
희동이/8/1
김영이/17/1
5-1) for문, get(), size() 같이 이용하기
stdList의 길이만큼까지 반복하는데 인덱스i번째 값을 반복하는 for문
//length를 반환하지 않기때문에 size를 쓴다
for(int i = 0; i<stdList.size() ; i++) {
System.out.println(stdList.get(i));
}
6) Object set(int index,E e)
리스트의 index 번째 요소를 e로 변경하고 기존에 있던 값을 반환
Object obj = stdList.set(0, new Student("이미니", 18, 2));
//stdList 0번째 인덱스에 있는값을 new Student로 바꾼다.
System.out.println("반환된 Object : " + obj);
System.err.println(stdList); //홍길동 대신 이미니가 들어가있다.
➡ set을 통해 변경되어진 값을 obj에 대입
결과
반환된 Object : 홍길동/15/2
[이미니/18/2, 박철수/13/6, 고길동/16/3, 희동이/8/1, 김영이/17/1]
7) Object remove(int index)
리스트의 index번째 요소를 삭제하고 기존에 있던 값을 반환
Object obj2 = stdList.remove(1);
System.out.println("제거된 학생 정보 : "+ obj2);//박철수 제거
System.out.println(stdList); //박철수 제거 확인
결과
제거된 학생 정보 : 박철수/13/6
[이미니/18/2, 고길동/16/3, 희동이/8/1, 김영이/17/1]
get에서 얻어오는 데이터의 자료형을 Object로 인식
자식안에있는 부모 모양만 참조한다 - 업캐스팅!!
(Student)stdList.get(i)-- 다운 캐스팅
** add에 다른 자료형도 추가
// *다른 자료형 추가
stdList.add("문자열도 객체다");
//컬렉션은 객체만 저장 가능하다.
stdList.add(new Integer(100)); // 100 (int) -- Auto Boxing --> 100 (integer)
// integer라는 wrapper 클래스 (이제는 잘 안쓰는데 예제용)
ArrayList list2 = new ArrayList();
list2.add( new Student("김갑수", 19, 3) );
list2.add( new Student("김삼순", 19, 3) );
stdList.add(list2); //컬렉션은 객체도 가능하다 => 그래서 위에서 만든 list2도 가능
// stdList에 저장된 정보 모두 출력
for(int i = 0; i <stdList.size(); i++) {
System.out.println(stdList.get(i));
}
// 결과
// 이미니/18/2
// 고길동/16/3
// 희동이/8/1
// 김영이/17/1 ---student
// 문자열도 객체다 --- string
// 100 ---integer
// [김갑수/19/3, 김삼순/19/3] -- arraylist
➡ 문자열은 기본자료형이 아닌 참조형으로 컬렉션에서 사용 가능
** stdList의 요소 중 Student 객체에 접근하는 경우 이름만 출력하기
System.out.println("stdList의 요소 중 Student 객체에 접근하는 경우 이름만 출력하기"); // 데이터가 길어지면서 관리는 어렵다
for(int i = 0; i<stdList.size(); i++) {
// stdList.get(i) --i번째 요소를 출력한다. -> 참조하고있는 인스턴스가 어떤 인스턴스인지 확인하는 instanceof사용
if( stdList.get(i) instanceof Student) {
//stdList의 i번째 요소가 Student 객체 또는 Student를 상속받은 객체인 경우
//ArrayList에 저장되는 데이터,데이터 타입은 모두 Object 타입으로 인식된다.
//(자료형 관계없이 모두 들어오게하기위해 Object타입으로 인식)
// stdList.get(i)를 통해서 얻어오는 데이터의 타입은 모두 Object
System.out.println( ( (Student) stdList.get(i) ).getName() );
//Object -> Student로 다운 캐스팅
} else {
System.out.println(stdList.get(i));
}
}
결과
// stdList의 요소 중 Student 객체에 접근하는 경우 이름만 출력하기
// 이미니
// 고길동
// 희동이
// 김영이
// 문자열도 객체다
// 100
// [김갑수/19/3, 김삼순/19/3]
8) 향상된 for문 (for each 문)
for( 하나씩 꺼내서 담을 변수 : 컬렉션 또는 배열명 )
- 컬렉션이나 배열의 모든 요소를 처음부터 끝까지 순서대로 접근하는 용도의 for문
굉장히 유용하고 꼭 알아둬야하고 컬렉션을 위해 존재
public void example3() { ArrayList list = new ArrayList(); list.add("김밥"); list.add("라면"); list.add("탕수육"); list.add("파스타"); // 1) 기존 for문 // 2) 향상된 for문 } // ==> 위에 노란줄은 정보표시줄
// list에 저장된 데이터를 모두 출력
1) 기존for문
for(int i = 0; i < list.size(); i++) { System.out.println( list.get(i) ); }
2) 향상된 for문
for( Object obj: list ) { // for문이 반복될 때 마다 list에 저장된 요소를 처음부터 순서대로 하나씩 꺼내 obj변수에 저장 System.out.println(obj); }
9) Generics(제네릭, 제네릭스, 지네릭스)
클래스, 메서드, 컬렉션 내부에 사용되는 클래스 타입을 한 종류로 제한하는 기능
-> 타입 제한
제네릭의 이점
1) 하나의 타입으로 제한이 되기 때문에 instanceof 같은 타입 검사, 다운캐스팅의 작업이 필요 없어진다.
-> 코드 활용 방법이 쉬워짐
== 컴파일 단계에서의 강력한 타입 체크
2) 하나의 코드로 여러 타입 처리가 가능하다. (다형성)
⭐ 컬렉션 타입 제한 기능의 제네릭 사용
public void example4() {
// ** 컬렉션 타입 제한 기능의 제네릭 사용
ArrayList<Student> stdList = new ArrayList<Student>();
// Student로 타입이 제한된 ArrayList 객체 생성
// == 생성된 ArrayList에는 Student만 저장 가능
// == 저장된 데이터는 모두 Student이다.
//add(Student e)
stdList.add( new Student("김아무개", 9, 2));
stdList.add( new Student("김스벅", 10, 3));
stdList.add( new Student("김투썸", 11, 4));
stdList.add( new Student("김할리스", 12, 5));
//향상된 for문으로 모두의 이름 출력
for(Student std : stdList ) {
// stdlist가 Student로 타입이 제한되어 있기 때문에
// 하나씩 순서대로 꺼내서 저장하는 변수의 타입도 Student 타입을 사용한다.
// Student 타입을 사용한다면 instanceof 검사가 필요 없다.
System.out.println( std.getName() );
// std가 Student 타입이기 때문에 다운 캐스팅이 필요 없다.
}
}
--
리스트는 인터페이스의 성질을 갖고있어서 ArrayList, Vector, LinkedList가 List의 성질을 갖는다.
예를들면 왼손, 오른손 둘 중 하나로 밥을 먹어도 밥을 먹는 행위는 된다.
--
10) 컬렉션과 다형성
- 다형성이란? - 부모 타입의 참조변수로 상속 관계에 있는 자식 객체를 참조하는것
- 인터페이스란? - 틀만 작성된 미완성의 설계도
- 인터페이스의 특징 : 상속받은 자식에게 동일한 이름의 기능을 강제적으로 오버라이딩 시킨다 -> 자식들의 형태가 비슷하다. + 객체 생성 x, 부모 타입 참조 변수 사용 O
ArrayList : 배열 모양의 List로 검색에 효율적이다.
LinkedList : 요소 하나 하나가 줄로 연결된 모양으로 추가, 삭제에 효율적이다.
🔎 List<String>
list -컬렉션 <strig> -다형성
1) 다형성 미적용 예제
public void example5() {
//ArrayList<String> list1 = new ArrayList<String>();
LinkedList<String> list1 = new LinkedList<String>();
// 추가
list1.add("AAA");
list1.add("BBB");
list1.add("CCC");
list1.add("DDD");
// 삭제
list1.remove(0);
list1.remove(0);
list1.remove(0);
//추가 삭제가 빈번하므로 LinkedList가 더 효율적임
--> 그래서 사용할 땐 위에 linkedlist로 하기
ex5_1(list1); // 매개변수로 ArrayList<String> 전달
list1 = ex5_2(); //반환값으로 ArrayList<String> 반환
}
//매개 변수가 ArrayList<String>인 메서드
//String으로 된 ArrayList를 받는다
public void ex5_1(LinkedList<String> list) {
System.out.println(list);
}
//반환형이 ArrayList<String>인 메서드
public LinkedList<String> ex5_2() {
return new LinkedList<String>();
}
// arraylist 에서 LinkedList로 변경하려면 총 5번 수정해야하는데 코드가 길어지면 이렇게 하는게 좋을까?
2) 컬렉션에 다형성 적용 예제
⭐ 컬렉션에 다형성 적용 시 이점
-> 유지 보수성 향상, 범용성 향상(어떤 list관련 코드에서든 사용가능)
public void exmaple6() {
List<String> list2 = new LinkedList<String>();
// 부모 타입(list) 참조 변수로 자식 타입 객체(ArrayList) 참조
// -> LinkedList로 자식 객체를 변경해도 문제가 발생하지 않는다.
// 이유 1. ArrayList, LinkedList 둘 다 List를 상속 받았기 때문에 사용하는 메서드의 이름이 같다.
// 이유 2. ex6_1, ex6_2() 두 메서드의 매개변수, 반환형이 부모 타입으로 작성되어 있기 때문에 참조하는 자식 객체가 변해도 다형성이 항상 적용된다.
// 추가
list2.add("AAA");
list2.add("BBB");
list2.add("CCC");
list2.add("DDD");
// 삭제
list2.remove(0);
list2.remove(0);
list2.remove(0);
//매개변수로 전달
ex6_1(list2);
//호출
list2 = ex6_2();
//부모타입으로 쓰여서 누가 들어와도 가능하다.
}
//매개 변수가 부모타입인 List<String> == 매개변수의 다형성
public void ex6_1( List<String> list) {
System.out.println(list);
}
//반환형이 부모타입인 List<String> ==반환형의 다형성
public List<String> ex6_2(){
return new ArrayList<String>();
}
3) Generic에 다형성 적용
하나의 코드로 여러 타입 처리가 가능하다. (다형성)는 Generic의 특징
public void example7() {
List<Person> list = new ArrayList<Person>();
// 제네릭이 부모타입인 Person으로 제한된 ArrayList객체를 생성
list.add(new Person('남', 180.5)); // 부모타입 객체 추가
list.add(new Student('여', 170, "주주주", 17, 1) ); // 자식 타입 객체 추가 -> 에러 없음
for(Person p : list) { //list안에 있는 값을 p에 담는다.
System.out.println(p.toString()); //
} // 정적 바인딩
}
결과
남/180.5 -person의 값 //참조변수도 person 값도 person
주주주/17/1/여/170.0 -- student의 값이나옴,
➡ person을 받는 p인데 왜 자료형인가?
참조변수는 부모인 person 참조당하는 객체는 자식객체 ==> 자식이 오버라이딩 했으니깐 자식쪽으로 이동
실행 중 오버라이딩 된 자식의 toString()가 연결됨 -> 동적 바인딩
동적 바인딩의 효과 : 하나의 코드로 여러 타입의 코드를 수행할 수 있다.
2. Vector
- List의 후손
- ArrayList와 동등하지만 동기화(Synchronized)를 제공한다는 점이 ArrayList와 차이점
List 객체들 중에서 가장 성능이 좋지 않음
3. LinkedList
- List의 후손
- 인접 참조를 링크해 체인처럼 관리 특정 인덱스에서 객체를 제거하거나 추가하게 되면 바로 앞/뒤 링크만 변경하면 되기 때문에
객체 삭제와 삽입이 빈번하게 일어나는 곳에서는 ArrayList보다 성능이 좋음
4. Comparable, Comparator
Collections.sort()
Collections.sort(List list) T객체에 Comparable을 상속받아 compareTo 메소드 재정의를 통해 정렬 구현 (단 한 개의 정렬) Collections.sort(List list, Comparator c) 지정한 Comparator클래스에 의한 정렬 (여러 개의 정렬)
'Backend > Java' 카테고리의 다른 글
[Java] Collection_Map (0) | 2021.10.06 |
---|---|
[Java] Collection_Set (0) | 2021.10.06 |
[Java] Scanner 주의사항/ .next()와 .nextline() 차이 (0) | 2021.09.16 |
[Java] Polymorphism(다형성)_ 업·다운 캐스팅, 인터페이스, 추상클래스·메서드, 바인딩 (0) | 2021.09.11 |
[Java] Inheritance(상속) (0) | 2021.09.09 |