if
문과 else
문자바 코드는 다른 프로그래밍 언어와 마찬가지로 순차적으로 위에서 아래로 실행된다. 조건문은 실행의 흐름을 바꿔 코드를 선택적으로 실행하는 방법을 제공한다.
if (특정 조건) {
// 특정 조건이 **만족되면 실행**할 코드 (true)
} else {
// 특정 조건이 **만족되지 않으면 실행**할 코드 (false)
}
else if
문에서 중요한 점은 순서대로 if 조건식을 검사하면서 만족되는 조건이 이쓰면 해당 조건에 맞는 코드를 실행하고 그렇지 않은 조건은 건너뛴다.
if (1번 조건) {
// 1번 조건이 만족되면 실행할 코드
} else if (2번 조건) {
// 2번 조건이 만족되면 코드 (false)
} else {
// 1, 2번 조건이 만족되지 않으면 실행할 코드
}
public class Main {
public static void main(String[] args) {
int number = 1;
if (number == 1) {
System.out.println("if 블록입니다.");
} else if (number == 2) {
System.out.println("else if 블록입니다.");
} else {
System.out.println("else 블록입니다.");
}
}
}
실행 결과 > if 블록입니다.
for
문과 while
문조건문과 함께 코드의 실행 흐름을 제어할 수 있는 것이 반복문이다. 조건문과는 조금 다르게 특정 조건이 만족되는 코드를 반복적으로 실행해야 할 때 사용한다.
for
문for (1. 최초 1회만 실행할 코드; 2. 반복 조건; 4. 1회 반복 후 실행할 코드) {
3. 반복 실행할 코드
}
public class Main {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5};
for (int i = 0; i < array.length; i++) {
System.out.println("i = " + array[i]);
}
}
}
while
문while (반복 조건) {
// 반복 실행할 코드
}
반복 조건이 참이면 반복하고, 그렇지 않으면 반복하지 않는다.
public class Main {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5};
int i = 0;
while (i < array.length) {
System.out.println("i = "+ array[i]);
i++;
}
}
}
앞서 적은 for문보다 더 복잡한 코드가 되었다.
while문은 언제 반복을 끝내야 할지 명확하지 않은 경우, 특정 조건만 만족하면 무한히 반복해야 하는 경우에 적합하다.
while (true) {
// 반복 실행할 코드
if (특정 조건) {
break;
}
}
주로 위와 같이 break문과 함께 사용된다.
자바스크립트랑 개똑같죠? 굿.
다형성의 기본 정의
: 하나의 객체가 내부적으로 여러 타입을 가질 수 있고, 어떤 타입이 들어 있느냐에 따라 각기 다른 동작을 하는 성질을 의미한다.
public interface Car {}
public class Sonata implements Car {}
public class K5 implements Car {}
public class Main {
public static void main(String[] args) {
Car car1 = new Sonata();
Car car2 = new K5();
}
}
인터페이스인 Car 타입의 참조 변수에 자동차 인터페이스의 구현체인 Sonata와 K5의 인스턴스를 모두 대입할 수 있다. 이것이 다형성이다.
Car를 부모 클래스로 바꾸고, 표현을'상속한다'로 바꾸더라도 다형성은 동일하게 적용된다.
Car는 인터페이스, Sonata와 K5는 Car라는 인터페이스를 구현(Implement)하는 구현체가 된다. 구현체는 클래스가 되고 인터페이스로는 new 키워드를 사용해 인스턴스를 생성할 수 없지만, 구현체인 클래스는 new 키워드를 사용해 인스턴스를 생성할 수 있다.
인터페이스나 추상 클래스는 메서드의 선언만 있고 실제 동작은 정의되어 있지 않다. 이를 실제로 작동하는 형태로 만든 클래스가 구현체이다.
클래스는 객체의 설계도로 객체가 가져야 할 상태(속성)과 행동(메서드)를 정의한다. 인스턴스는 클래스에 의해 생성된 실체로, 클래스의 정의를 바탕으로 실제 메모리 상에 할당된 객체를 의미한다. 클래스에는 속성과 메서드가 정의되어 있지만 클래스 자체만으로는 실제 작업을 수행할 수 없다. 클래스를 바탕으로 생성된 인스턴스는 실제로 속성을 갖고 메서드를 수행할 수 있다.
다형성의 장점
인터페이스(혹은 부모 클래스)의 참조 변수로 구현 클래스(혹은 자식 클래스)의 인스턴스를 넣어 사용할 수 있다.
일단 이 정도로 이해해두고... 넘어가세요...
if문이 없더라도 경우에 따라 다른 코드가 실행되도록 만들 수 있어서 코드가 복잡해지는 것을 막을 수 있다.
자바의 컬렉션은 데이터의 집합을 의미한다. List, Set, Map이 주요 컬렉션인데 이것은 모두 구현체가 아닌 인터페이스이다.
인터페이스를 구현하는 여러 클래스 중 가장 많이 사용되는 List 인터페이스의 구현체 ArrayList는 배열처럼 여러 개의 데이터를 다룰 때 주로 사용된다.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List list = new ArrayList<Integer>();
// <Integer>는 ArrayList에 Integer 타입이 저장될 수 있다는 것을 의미한다.
list.add(1);
list.add(2);
list.add(3);
System.out.println(list.get(1));
}
}
이름처럼 코드 내부에서 배열로 처리되고, 그 인터페이스가 List이다.
List와 ArrayList는 기본으로 import되는 인터페이스와 클래스가 아니다. 때문에 직접 불러와 줘야 한다.
import java.util.ArrayList; import java.util.List;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List list = new ArrayList<String>();
list.add("public"); // ["public"]
list.add("static"); // ["public", "static"]
list.add("void"); // ["public", "static", "void"]
// for 문으로 List를 순회할 수 있다.
for (int i = 0; i < list.size(); i++) { // list.size()는 리스트의 크기를 반환한다.
System.out.println(list.get(i)); // i번째 요소가 출력된다.
}
list.remove(1); // 1번째 요소인 "static"이 제거된다. -> ["public", "void"]
int voidIndex = list.indexOf("void"); // void의 인덱스인 1이 반환된다.
System.out.println("void의 index = " + voidIndex);
}
}
실행 결과 >
public
static
void
void의 index = 1
자바에서 동일하다고 말하는 경우는 같은 인스턴스를 참조하고 있을 때이다.
동일성 비교
public class Main {
public static void main(String[] args) {
String str1 = new String("is same?");
String str2 = new String("is same?");
System.out.println(str1 == str2); // true or false?
}
}
실행 결과 > false
str1은 "is same?"이라는 String 인스턴스를 생성하여 참조하고, str2는 "is same?"이라는 또 다른 String 인스턴스를 생성하여 참조한다. 때문에 String 인스턴스가 같은 값을 가지고 있더라도 각각 생성되었기 때문에 서로 다른 인스턴스인 것이다.
String 인스턴스의 값을 비교하려면 ==
가 아니라 equals()
메서드로 비교해야 한다. equals()
는 동일성이 아니라 동등성을 비교한다.
동등성 비교
public class Main {
public static void main(String[] args) {
String str1 = new String("is same?");
String str2 = new String("is same?");
System.out.println(str1.equals(str2)); // true or false?
}
}
실행 결과 > true
주의할 점
String 클래스는 자바에서 기본으로 제공해주는 String 클래스에 구현된
equals()
를 사용한다.
반면 내가 만든 클래스에 있는equals()
메서드는 Object 클래스로부터 상속받은 것이다. 때문에 Object 클래스에 상속된equals()
메서드는 내가 만든 클래스의 동등성을 비교하기에 적절치 않다.
따라서 반드시 내가 만든 클래스를 위한equals()
메서드를 오버라이딩 해줘야 하며,hashCode()
메서드 역시 함께 오버라이딩 해주는 것이 좋다.
🧐 왜
hashCode()
메서드를 오버라이딩 해줘야 할까?
→ 컬렉션 중 Hash로 시작하는 컬렉션인 HashMap, HashTable, HashSet는 동일한 값을 비교하기 위해hashCode()
메서드와equals()
메서드를 모두 사용한다. 만약equals()
메서드만 오버라이딩 하고hashCode()
메서드는 오버라이딩 하지 않는다면 Hash로 시작하는 컬렉션에서 같은 값으로 판단해야 할 인스턴스들이 마치 다른 인스턴스인 것처럼 동작할 것이다.
추가설명 : HashSet, HashMap과 같은 해시 기반의 자료구조에서는 객체의 해시 코드 값을 기반으로 저장, 검색을 수행한다. 내부적으로
hashCode()
를 사용해서 해시 코드를 알아내고 버킷을 찾은 후,equals()
메서드를 이용해 데이터를 찾는다. 따라서 재정의 한 메서드를 적절히 구현한다면 같은 객체를 같은 버킷에 매핑하여 검색 속도를 높일 수 있다. 출처: https://tecoble.techcourse.co.kr/post/2020-07-29-equals-and-hashCode/, https://everydayyy.tistory.com/153
<이것이 백엔드 개발이다 with 자바> 책을 공부하고 정리한 내용입니다.