🚀 제대로 파는 자바(Java) - by 얄코 강의를 듣고 정리한 내용입니다.
코딩테스트공부 관계로 앞서 공부하던 객체지향보다 우선해서 리스트를 공부하려 한다.
// ⭐️ 제네릭을 사용하여 타입 지정
// - 붙이지 않을 시 <Object>와 동일
// 제너릭으로 원시타입은 들어갈 수 없음
ArrayList<Integer> ints1 = new ArrayList<>();
ArrayList<String> strings = new ArrayList<>();
ArrayList<Number> numbers = new ArrayList<>();
ArrayList<Knight> knights = new ArrayList<>();
// add 메소드로 요소 추가
ints1.add(11);
ints1.add(22);
ints1.add(33);
ints1.add(44);
ints1.add(55);
// 요소 중복 허용
for (var str : "바니 바니 바니 바니 당근 당근".split(" ")) {
strings.add(str);
}
// for-each 문 사용 가능
for (int i : ints1) {
System.out.println(i);
}
아래에 있는 메소드들을 잘 외우자.
int ints1Size = ints1.size(); // 요소 개수
boolean ints1IsEmpty = ints1.isEmpty(); // size가 0인지 여부 반환
int ints12nd = ints1.get(1); // 인덱스로 요소 접근
boolean ints1Con3 = ints1.contains(33); // 포함 여부
boolean ints1Con6 = ints1.contains(66);
ints1.set(2, 444); // 인덱스 위치의 요소 수정
ints1.add(0, 11); // 인덱스 위치에 요소 추가 (다음 요소들 밀어냄)
// ⭐️ 간략한 생성 및 초기화 방법들
ArrayList<Integer> ints2A = new ArrayList<>(
Arrays.asList(1, 2, 3, 4, 5)
); // 💡 Arrays 클래스 : 배열 관련 각종 기능 제공
ArrayList<Integer> ints2B = new ArrayList<>(
List.of(1, 2, 3, 4, 5)
); // 💡 자바9에서부터 가능
ArrayList<Integer> ints2C = new ArrayList<>();
Collections.addAll(ints2C, 1, 2, 3, 4, 5);
이번에는 기존에 존재하는 ArrayList를 가지고 새 ArrayList를 만드는 것을 볼 것이다.
// 💡 다른 Collection 인스턴스를 사용하여 생성
ArrayList<Integer> ints3 = new ArrayList<>(ints1);
// 스스로를 복제하여 반환 (⚠️ 얕은 복사)
ArrayList<Integer> ints4 = (ArrayList<Integer>) ints3.clone();
이번에는 요소를 지우는 것을 알아보겠다.
ints3.remove(4); // int: 인덱스로 지우기
ints3.remove((Integer) 55); // 클래스 자료형: 요소로 지우기 (들어온 값과 같은 첫번째 값을 지움)
위의 경우는 Integer의 값을 지워주는 경우라 (Integer) 를 붙여주어야 하지만, 다른 종류의 자료형들은 그냥 해당자료형의 값을 넣어주면 되니까 조금 덜 번거로울 것이다.
ints1.removeAll(ints3); // 주어진 콜렉션에 있는 요소들 지우기
위의 경위와는 반대로 요소를 이어붙일수도 있다.
ints1.addAll(ints3); // 콜렉션 이어붙이기
이제 배열로 반환하는 것을 알아보겠다.
// 💡 toArray - Object 배열 반환
Object[] intsAry2_Obj = ints1.toArray();
// ⭐️ 특정 타입의 배열로 반환하려면?
// Integer[] ints1Ary1 = (Integer[]) ints1.toArray(); // ⚠️ 이렇게는 불가
// 💡 인자로 해당 타입 배열의 생성자를 넣어줌
// - 다음 섹션에 배울 메소드 참조 사용 (9-3강 수강 후 다시 볼 것)
Integer[] ints1Ary2 = ints1.toArray(Integer[]::new);
위에서 알 수 있듯이 네번째 줄처럼 특정 타입으로 반환하는 것은 불가능한 것을 알 수 있다. 컴파일단계에서는 오류가 나지 않지만 런을 해보면 오류가 난다.
아래에 Integer[]::new 이 표현은 Integer 의 생성자를 축약해서 표현한 것이다.
아래는 리스트의 요소를 비우는 방법이다.
ints1.clear(); // 리스트 비움
아래처럼 각 컬렉션에 그에 맞지 않는 자료형을 넣어주면 오류가 나는 것을 알 수 있다.
// 제네릭 적용
numbers.add(Integer.valueOf(123));
numbers.add(3.14);
numbers.add("Hello"); // ⚠️ 불가
knights.add(new Swordman(Side.BLUE)); // ⚠️ 불가
knights.add(new Knight(Side.BLUE));
knights.add(new MagicKnight(Side.RED));
아래에서는 조금 중요한 개념이 나온다.
// ⭐️ 인스턴스 요소를 지울 때는 참조를 기준으로
// - 내용이 같다고 같은 인스턴스가 아님
Knight knight1 = new Knight(Side.RED);
knights.add(knight1);
// 요소가 하나 지워졌는지 여부 반환
boolean removed1 = knights.remove(new Knight(Side.RED));
boolean removed2 = knights.remove(knight1);
위에 내용을 디버깅해보면 알 수 있지만 참조형 데이터들이 컬렉션 안에 들어있을 때 remove 등에서 그것과 같은 것을 선택하는 기준은 인스턴스의 내용이 아니라 참조값, 즉 같은 주소에 위치하는 것인가를 보는 것이다.
따라서 두번째 remove에서는 knight1을 그대로 넣어줬다. 그러니 제대로 remove가 동작하였다.

큐를 구현하는 용도로 사용 가능
메모리 이곳저곳에 분산되어 배치
기능상 ArrayList와 대다수 주요 기능 공유
요소를 삭제하면 그 다음 요소들의 인덱스가 자동으로 조정되어 삭제한 요소의 다음 요소가 해당 인덱스로 이동한다.

각 요소들이 메모리 이곳저곳에 산재
용도
위의 예제들에서 ArrayList를 전부 LinkedList로 변경해도 정상작동하는 것을 볼 수 있다.
이제 아래에는 ArrayList와 LinkedList 각각에 고유하게 존재하는 것들이다.
// ⭐️ 둘의 차이와 연관지어 생각해 볼 것
// 💡 ArrayList에만 있는 메소드들 중...
ArrayList<Attacker> attackers = new ArrayList<>();
// 자주 쓰이지는 않음
attackers.ensureCapacity(5); // 자리수 미리 확보
attackers.trimToSize(); // 남는 자리 없애기 (메모리 회수)
// 💡 LinkedList에만 있는 메소드들 중...
LinkedList<Integer> intNums = new LinkedList<>();
for (var intNum : new int[] {2, 3, 4}) { intNums.add(intNum); };
intNums.addFirst(1);
intNums.addFirst(0);
intNums.addLast(5); // add와 반환값만 다름. 코드에서 확인해 볼 것
intNums.addLast(6);
// 💡 앞에서/뒤에서 꺼내지 않고 반환
// - peek~ : 비어있을 경우 null 반환
// - get~ : 비어있을 경우 익셉션
int peekedFirst = intNums.peekFirst();
int gottenFirst = intNums.getFirst();
int peekedLast = intNums.peekLast();
int gottenLast = intNums.getLast();
// 💡 앞에서/뒤에서 꺼내어 반환
// - poll~ : 비어있을 경우 null 반환
// - remove~ : 비어있을 경우 익셉션
int polledFirst = intNums.pollFirst();
int removedSecond = intNums.removeFirst();
int polledLast = intNums.pollLast();
int removedLast = intNums.removeLast();
// ⭐️ 위의 기능들 활용하여 Stack/Queue 구현
LinkedList<Character> charLList = new LinkedList<>();
// 💡 push & pop : 스택 간편하게 구현
// - 클래스 코드에서 살펴볼 것
charLList.push('A'); // addFirst
charLList.push('B');
charLList.push('C');
charLList.push('D');
charLList.push('E');
char pop1 = charLList.pop(); // removeFirst
char pop2 = charLList.pop();
char pop3 = charLList.pop();
List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5);
ArrayList<Integer> list2 = new ArrayList<>(list1);
var list1Type = list1.getClass().getName();
var list2Type = list2.getClass().getName();
list1.add(6); // ⚠️ 런타임 오류
List<Integer> intList = new ArrayList<>();
intList = new LinkedList<>();
Set<String> strSet = new HashSet<>();
strSet = new TreeSet<>();
Map<Integer, String> intStrMap = new HashMap<>();
intStrMap = new TreeMap<>();