-
Iterable과 Iterator
Java Collection Framework 상위에 Iterable 인터페이스가 존재한다. Iterable 인터페이스 안에는 Iterator 추상 메소드가 존재한다. 따라서 Collection 인터페이스 계층구조에서 구현된 클래스들은 모두 iterator 메소드를 가지고 있다. 따라서 이 클래스들은 모두 Iterator를 사용할 수 있다. (단 map이나 set은 key, value로 이루어져있기 때문에 직접 iterator를 호출할 수없고 keySet이나 entrySet 메서드를 이용해 사용한다.)
이를 사용한 이유는 Java Collection Framework에 저장된 데이터를 읽어오는 방법을 표준화하고 싶기 때문이다.
Iterator Method
hasNext() : 읽어 올 요소가 남아있는지 확인한다.
next() : 다음 데이터를 반환한다.
remove() : next()로 읽어온 요소를 삭제한다. 이는 next()를 호출한 다음에 remove()를 호출해야 한다.
public interface Iterable<T> { Iterator<T> iterator(); } public interface Iterator<E> { boolean hasNext(); E next(); void remove(); }
For vs For Each
for Loop
for(초기 값; 조건; 증감 연산자) { --- } for(int i=0;i<array.size();i++) { --- }
초기에 초기값을 기준으로 시작하여 조건을 만족하지 않을떄까지 증감 연산자를 진행한다. 하지만 위 코드에서는 loop마다 size method를 계속하여 호출하는 단점이 있다. 따라서 size method를 다른 변수에 저장하여 변수를 조건식에 넣어 사용하는것이 좋다.
For Each
Linked List에서는 for문이 아닌 for each를 사용하는 것이 좋다. 왜냐하면 각 index마다 linked list의 get 메서드를 사용하면 매번 Head부터 탐색을 다시 진행하기 때문이다. 이로인해 O(n^2)의 cost가 발생된다.
동작원리
Iterator를 사용하고 1, 2 단계를 반복한다.
1. hasNext method로 다음 값이 존재하는지 확인한다. 만약 다음 값이 없을 경우의 종료한다.
2. next method로 cursor의 위치를 바꾼다.
이때 순회 도중 자료구조의 값이 변형되면 안된다.
for (int i=0;i<list.size();i++) { list.get(i) } for (int num : array) { //num }
==, equals(), hashcode() 차이점
== 연산자
Primitive Type(int, double, boolean, ...)일 때는 값이 같은지 비교를 하고, Reference Type일 때 가리키는 주소가 같은지를 검사한다. string은 Primitive type이 아니다.
하지만 string의 경우 조금 차이점이 있다. string은 리터럴로 생성된 객체로 Heap에 생성된 "hello"를 같이 가리키고 있다. 따라서 str1과 str2가 같다고 할 수 있다. 즉 str1, str2는 같은 주소이다.
반면 str3와 str4는 각각 다른 주소를 갖는 객체이므로 str3는 str4와 다르게 나온다.
String str1 = "hello"; String str2 = "hello"; System.out.println(str1 == str2);//true String str3 = new String("hello"); String str4 = new String("hello"); String str5 = str4; System.out.println(str3 == str4);//false System.out.println(str4 == str5);//true
equals()
default로 primitive type은 내용이 같은지 검사 하고, reference type은 내용이 같은지를 검사한다..
Subject subject1 = new Subject("math", 80); Subject subject2 = new Subject("math", 80); System.out.println(subject1 == subject2);//false System.out.println(subject1.equals(subject2));//false
위 코드에서 두 값은 다르다고 나온다. == 연산은 reference type의 경우 주소 값을 비교하니 당연히 아니다. equlas함수는 내용을 비교하지만 자바는 위 내용이 같은지를 모르기 때문이다. 따라서 equals() 메서드를 오버라이드해서 두 객체의 내용이 같은지를 올바르게 재정의 해야 작동한다.
추가로 String은 클래스 내부적으로 equals 메서드를 오버라이드했기 때문에 두 값이 같은지에 대해 따로 오버라이드 할 필요가 없다.
따라서 두 객체의 내용이 같은지를 비교하기 위해서는 오버라이드하여 재정의 할 필요가 있다. 이때 equals()와 hashcode()를 함께 재정의 해야한다.
왜냐하면 hash를 사용하는 Collection(HashSet, HashMap 등)에서 hash value가 다르지만 값이 같다고 나올 수 있기 때문이다.
즉, equals로 같은 객체라면 hashcode 역시 같아야한다. (hashcode가 같더라도 두 객체가 다를 수 있다.)
'Java' 카테고리의 다른 글
Chapter 3. Java Virtual Machine (0) 2021.07.04 Chapter 2. Java Memory & Variable Type (0) 2021.07.04 Chapter 1. Object Oriented Programming (0) 2021.07.04