위 표에서 배열에서 인덱스를 사용하는 경우 가 가장 이상적이며 (최고의 효율이 나옴)
인덱스를 사용할 수 있다면 최대한 활용하는 것이 좋다
한번 크기를 지정하면 변경 x
데이터에 대한 중간위치의 추가, 삭제가 불편하다.
한 타입의 데이터만 저장 가능하다.
컬렉션
- 자바에서 제공하는 자료구조를 담당하는 프레임워크
- 추가, 삭제, 정렬 등의 기능처리가 간단히 해결되어 자료구조적 알고리즘을 구현할 필요 없음
- java.util 패키지에 포함되며, 인터페이스를 통해 정형화된 방법으로 다양한 컬렉션 클래스 이용
- 여러 타입의 데이터가 저장 가능하며 저장하는 크기의 제약이 없다

ArrayList people = new ArrayList(); // 리스트 저장공간 만들어줌
people.add(new Person("aa",50,'남',180.5)); // 값 저장할때 add메소드 사용 => 인덱스 알아서 늘려줌
people.add(2, new Person("bb",70,'여',177.3)); // 2번째에 값추가하고 그 2번째부터 뒤로 자동으로 밀림
ArrayList people = new ArrayList();
System.out.println(people.get(0)); // 0번째 인덱스에 있는 값 가져오기
// 전체 출력 방법 3가지
// (1) : for문 + get()함수 + size()함수 사용
// people.get(i) 출력시 -> Person 클래스의 toString 함수가 출력됨
// Person 클래스의 toString 오버라이딩 함수가 없으면 Object의 toString이 호출되서 주소값 출력
for(int i=0; i<people.size(); i++) {
Person p = (Person)people.get(i);
System.out.println(p.getName()+" "+p.getAge()+" "+p.getGender()+" "+
p.getHeight()+" "+p.getWeight());
}
// (2) : for-each 문
for(Object o : people) {
Person p = (Person)o;
// people 자체는 반환형이 Object 타입이기 때문에 왼쪽 오른쪽에 서로 Objcet로 맞춰준다
// Person 안의 set,get함수 사용하기 위해서
// Object 타입을 Person 타입으로 형변환 시켜준다.
System.out.println(p.getName()+" "+p.getAge()+" "+p.getGender()+" "+
p.getHeight()+" "+p.getWeight());
}
// (3) : for-each 메소드 사용
// forEach()는 Consumer라는 함수형 인터페이스를 인자로 받음
// Consumer 함수형 인터페이스 -> 1개의 인자를 받고 리턴값이 없는 accept() 메소드를 갖고 있음
// accept() -> 추상 메서드임
// Consumer은 단지 매개값을 소비하는 역할만 하며, 사용만하고 리턴값이 없음
// 밑에 사진 참고
// people의 toString() 오버라이딩 부분을 깔끔하게 수정해서 출력하면 잘 나온다.
people.forEach((o)-> System.out.println(o));
// (4) : iterator() 메소드 사용 (Iterator 객체를 이용)
Iterator it = people.iterator(); // 0번~마지막까지 모든 인덱스를 이터레이터 방식으로 뽑음
while(it.hasNext()) { // 다음 뽑을 객체가 있다면
Person a = (Person)it.next(); // 그 다음값을 형변환해서 Person 객체로 형변환한 후
System.out.println(a); // 출력
// System.out.println(it.next()); // it.next()를 두번 출력하면 데이터의 개수가 홀수 일 경우
// System.out.println(it.next()); // java.util.NoSuchElementException 예외가 발생
}
((Person)people.get(0)).setAge(20); // 이와 같은 형변환 방식으로 값을 바꿀 수 있음


ArrayList people = new ArrayList();
if(people.isEmpty()) {
System.out.println("사람 없어요~");
}else {
System.out.println("사람 있어요~");
}
// 위 리스트에는 데이터가 없기 때문에 사람 없어요가 출력됨!
//위 isEmpty 메소드와 비슷하게 사용할 수 있는 메서드 : size();
if(people.size() == 0) { // isEmpty() 메소드와 기능 동일
System.out.println("사람 없어요~");
}
if(people.size() > 0) { // 1개이상 있다는 말 -> 비어있지 않다는 말
System.out.println("사람 있어요~");
}
people.set(3, new Person("cc",90,'남',175.3)); // 3번째 인덱스 값에 넣어버리고 원래있던 값은 삭제
people.remove(4); // 4번째 인덱스에 있는 값 삭제
// 해당 객체가 있는 위치의 인덱스에 있는 값 삭제
people.remove(people.indexOf(new Person("김두환",43,'남',188.2)));
// 매개변수와 일치하는 값 삭제하기
// remove(Object o) -> 대상 클래스에 equals, hashCode가 오버라이딩 되어있어야한다.
// 대상 Person 클래스안에 equals와 hashCode가 오버라이딩 되어있어야함
people.remove(new Person("주몽",58,'남',189.4); // 해당 대상 삭제
// contains(Object) : boolean형으로 반환함
if(people.contains(new Person("고길동",20,'남',175.5))) {
System.out.println("이미 존재하는 사람입니다."); // 해당 고길동 정보들이 있을시 문구 출력
}else {
people.add(new Person("고길동",20,'남',175.5)); // 없으면 리스트의 마지막에 추가
}
// indexOf(Object) -> 해당 객체를 못찾으면 -1로 리턴
int index = people.indexOf(new Person("선덕여왕",35,'여',150.2));
people.clear();
Object[] objArr = people.toArray(); // ArrayList가 배열로 변환됨
boolean flag = false;
for(int i=0; i<objArr.length; i++){
if(objArr[i] != null) {
flag = true;
}
}
String msg = (flag == true) ? "사람있어요" : "사람없어요";
System.out.println(msg);
List people1 = Arrays.asList(objArr); // 배열 objArr이 ArrayList로 변환됨
// Collection, List 인터페이스는 부모타입으로
// ArrayList 객체를 저장할 수 있다.
Collection c; // = new Collection(); // 이런식으로 객체를 스스로 생성은 불가능함(인터페이스이므로)
c = new ArrayList();
List intList = List.of(1, 2, 3, 4, 5); // 고정값임 (수정이 불가능함) = final
List animalList = List.of(new Animal(), new Animal(), new Animal());
// animalList 배열의 주소값을 수정불가능한것이지, 안에있는 값들은 변경가능함
((Animal) animalList.get(0)).setName("햄찌"); // 이와 같이 안에 값들은 변경 가능
// 값을 비교할 기준을 정해줘서 Comparator을 재정의해줌
// 1. Comparator를 구현한 클래스 생성하기
foods.sort(new FoodPriceAes()); // FoodPriceAes 클래스를 통해서 가격을 기준으로 오름차순
System.out.println("===== 정렬후 =====");
for(Object o : foods) {
System.out.println(o);
}
// FoodPriceAes 클래스 (가격 오름차순)
public class FoodPriceAes implements Comparator{ // Comparator 인터페이스를 구현해야함
@Override
public int compare(Object o1, Object o2) {
Food f = (Food)o1;
Food f2 = (Food)o2;
// 가격 기준으로 정렬
// 반환값설정
// + : 두개의 객체 위치 변경
// -,0 : 변경하지 않음
// 오름차순정렬 : 앞에있는것이 크면은 +기 때문에 자리빠꿔야함 -> 즉 오름차순임
if(f.getPrice() > f2.getPrice()) return +1; // 두 위치를 바꿈
else if(f.getPrice() < f2.getPrice()) return -1; // 변경하지 않음
else return 0; // 변경하지 않음
}
// FoodNameAscending 클래스 (이름 오름차순)
public class FoodNameAscending implements Comparator{
@Override
public int compare(Object o1, Object o2) { // compare 추상 메소드 구현해줌
Food prev = (Food)o1;
Food next = (Food)o2;
return prev.getName().compareTo(next.getName()); // 이름순으로 오름차순
// compareTo() 메서드는 문자열의 사전순 값을 비교하여 그에 해당되는 int 값을 리턴
// A=A = 0 (동일한 경우)
// A>B = 1 (좌측값이 큰 경우)
// A<B = -1 (좌측값이 작은 경우)
}
// (2) 클래스를 생성하지 않고 익명클래스로 생성해서 만드는 방법
foods.sort(new Comparator() {
@Override
public int compare(Object o, Object o1) {
Food f = (Food)o;
Food f2 = (Food)o1;
return f.getPrice()-f2.getPrice();
}
});
// (3) 람다식으로 출력하는 방법
foods.sort((o,o2)-> ((Food)o).getName()
.compareTo(((Food)o2).getName()));
이중 연결구조를 가진다node.next = 다음노드node.prev = 이전노드
✅ ArrayList와 LinkedList의 차이점
- ArrayList 는 배열형식이며 순차적으로 인덱스 구조를 가짐
- LinkedList 는 앞뒤로 서로 연결되있는 구조
- 둘의 차이는 수정할때 퍼포먼스 속도 차이가 남
- 저장된 데이터를 조작(중간에 삽입, 수정, 삭제)이 많을 때는 LinkdeList 사용하는것이 좋다
- 기본적으로 데이터를 저장, 출력할 때에는 ArrayList 사용
LinkedList linkList = new LinkedList();
linkList.add("aa");
linkList.add("bb");
linkList.add("cc");
System.out.println(linkList.get(0)); // aa
System.out.println(linkList.getFirst()); // aa
System.out.println(linkList.getLast()); // cc
✅ 컴파일 타임 의존관계
BatchProcessor 클래스를 보면 MyList 인터페이스만 사용한다MyArrayList, MyLinkedList 같은 정보는 보이지 않는다BatchProcessor는 MyList 인터페이스에만 의존한다
✅ 런타임 의존관계
// BatchProcessor 클래스
public class BatchProcessor {
private final MyList<Integer> list;
public BatchProcessor(MyList<Integer> list) {
this.list = list;
}
public void logic(int size) {
long startTime = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
list.add(0, i); //앞에 추가
}
long endTime = System.currentTimeMillis();
System.out.println("크기: " + size + ", 계산 시간: " + (endTime - startTime)
+ "ms");
}
}
// main문
MyArrayList<Integer> list = new MyArrayList<>();
BatchProcessor processor = new BatchProcessor(list);
processor.logic(50_000);

BatchProcessor 인스턴스의 MyList list는 생성자를 통해 MyArrayList 인스턴스를 참조한다
BatchProcessor 인스턴스에 MyArrayList 의존관계를 주입한다
따라서 이후 logic()을 호출하면 MyArrayList 인스턴스를 사용하게 된다
쉽게말해서 BatchProcessor 클래스는 구체적인 MyArrayList나 MyLinkedList에 의존하는 것이 아니라
추상적인 MyList에 의존하며, 런타임에 MyList의 구현체를 얼마든지 선택할 수 있다
의존관계를 클래스에서 미리 결정하는 것이 아니라, 런타임에 객체를 생성하는 시점으로 미룬다
따라서 런타임에 MyList의 구현체를 변경해도 BatchProcessor의 코드는 전혀 변경하지 않아도 됨
이렇게 생성자를 통해 런타임 의존관계를 주입하는 것을 생성자 의존관계 주입 또는 생성자 주입이라 한다
위 코드는 디자인 패턴중 전략 패턴 에 속한다