위 표에서 배열에서 인덱스를 사용하는 경우
가 가장 이상적이며 (최고의 효율이 나옴)
인덱스를 사용할 수 있다면 최대한 활용하는 것이 좋다
한번 크기를 지정하면 변경 x
데이터에 대한 중간위치의 추가, 삭제가 불편하다.
한 타입의 데이터만 저장 가능하다.
컬렉션
- 자바에서 제공하는 자료구조를 담당하는 프레임워크
- 추가, 삭제, 정렬 등의 기능처리가 간단히 해결되어 자료구조적 알고리즘을 구현할 필요 없음
- java.util 패키지에 포함되며, 인터페이스를 통해 정형화된 방법으로 다양한 컬렉션 클래스 이용
- 여러 타입의 데이터가 저장 가능하며 저장하는 크기의 제약이 없다
ArrayList people = new ArrayList(); // 리스트 저장공간 만들어줌
people.add(new Person("유병승",19,'남',180.5,65.5)); // 값 저장할때 add메소드 사용 => 인덱스 알아서 늘려줌
people.add(2, new Person("최주영",26,'남',177.3,70.5)); // 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("이동제",25,'남',175.3,68.3)); // 3번째 인덱스 값에 넣어버리고 원래있던 값은 삭제
people.remove(4); // 4번째 인덱스에 있는 값 삭제
// 해당 객체가 있는 위치의 인덱스에 있는 값 삭제
people.remove(people.indexOf(new Person("김두환",43,'남',188.2,95.5)));
// 매개변수와 일치하는 값 삭제하기
// remove(Object o) -> 대상 클래스에 equals, hashCode가 오버라이딩 되어있어야한다.
// 대상 Person 클래스안에 equals와 hashCode가 오버라이딩 되어있어야함
people.remove(new Person("주몽",58,'남',189.4,90.3)); // 해당 대상 삭제
// contains(Object) : boolean형으로 반환함
if(people.contains(new Person("고길동",20,'남',175.5,70.5))) {
System.out.println("이미 존재하는 사람입니다."); // 해당 고길동 정보들이 있을시 문구 출력
}else {
people.add(new Person("고길동",20,'남',175.5,70.5)); // 없으면 리스트의 마지막에 추가
}
// indexOf(Object) -> 해당 객체를 못찾으면 -1로 리턴
int index = people.indexOf(new Person("선덕여왕",35,'여',150.2,50.5));
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("최주영");
linkList.add("이동제");
linkList.add("최인호");
System.out.println(linkList.get(0)); // 최주영
System.out.println(linkList.getFirst()); // 최주영
System.out.println(linkList.getLast()); // 최인호
✅ 컴파일 타임 의존관계
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
의 코드는 전혀 변경하지 않아도 됨
이렇게 생성자를 통해 런타임 의존관계를 주입하는 것을 생성자 의존관계 주입
또는 생성자 주입
이라 한다
위 코드는 디자인 패턴중 전략 패턴
에 속한다