코드스테이츠 수강 5주차 1일차에는 열거형, 제네릭, 예외 처리, 컬렉션 프레임워크에 대해 배웟다.
1. 열거형
열거형은 서로 연관된 상수의 집합을 의미한다.
상수는 변하지 않는 값으로, final 키워드로 선언 할 수 있다.
열거형은 상수들을 간편하게 관리할 때 유용하게 사용될 수 있고, 변하지 않는 데이터를 다룰 때 사용된다.
열거형을 사용하지 않고 상수를 설정하게 되면
코드예시
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int FALL = 3;
public static final int WINTER = 4;
public static final int DJANGO = 1;
public static final int SPRING = 2; // 계절의 SPRING과 중복 발생!
public static final int NEST = 3;
public static final int EXPRESS = 4;
위의 코드처럼 final 키워드로 int형 데이터를 상수로 지정 한 것을 볼 수 있다.
여기서 문제점이 있는데, 변수명에 따라 중복될 수 있어 컴파일 에러가 발생할 수 있다.
물론, 이 경우 인터페이스를 사용해서 상수를 구별해서 사용하면 어느정도 해결된다.
interface Seasons {
int SPRING = 1, SUMMER = 2, FALL = 3, WINTER = 4;
}
interface Frameworks {
int DJANGO = 1, SPRING = 2, NEST = 3, EXPRESS = 4;
}
하지만 이 경우 또또 문제가 생긴다.
인터페이스로 별도로 만들어놓은 변수이기 때문에 타입 안정성이 떨어진다는 것이다.
if (Seasons.SPRING == Frameworks.SPRING) {...생략...}
계절의 SPRING(봄) , 프레임워크의 SPRING은 서로 의미가 다른데도 비교가 가능해지는 것이다. (인터페이스에서 그냥 따로 선언한 것 뿐이지 사실 둘다 int형 자료이기 때문에)
쉽게 말하면 이 사진과 비슷하다.
이 문제를 해결하려면, 저 위의 변수들을 서로 다른 클래스에 저장해서 상수로 선언하면 된다.
그런데, 이러면 코드도 길어지고, switch문을 못쓴다.
class Seasons {
public static final Seasons SPRING = new Seasons();
public static final Seasons SUMMER = new Seasons();
public static final Seasons FALL = new Seasons();
public static final Seasons WINTER = new Seasons();
}
class Frameworks {
public static final Frameworks DJANGO = new Frameworks();
public static final Frameworks SPRING = new Frameworks();
public static final Frameworks NEST = new Frameworks();
public static final Frameworks EXPRESS = new Frameworks();
}
변수 8개를 주제에 맞게만 저장하면 되는데, 인터페이스로는 타입 안정성이 떨어지고, 클래스로 하면 코드 개판나고 스위치문 못쓴다.
(클래스로 선언하면 스위치문 못쓰는 이유: 스위치문은 정해진 타입만 넣어서 돌릴 수 있는데, 클래스로 선언하면 사용자 정의타입이기 때문이다. (사전에 자바 안에 정해져 있지 않다.)
아주 뭐 답답한 상황이다.
이를 해결하기 위해 열거형 enum이 있다!
작성예시
enum Seasons { SPRING, SUMMER, FALL, WINTER }
enum Frameworks { DJANGO, SPRING, NEST, EXPRESS }
간단히 다른 변수명을 선언하는것 처럼 enum (변수명) {내용} 으로 처리하면 된다.
이렇게 하면 타입안정성이 확보되고, 코드도 짧아져서 가독성도 높고, 스위치문도 사용 가능하다!
enum을 switch 문에 적용 한 예시
enum chicken{
fried,
sauce,
onion
}
public class EnumTest {
public static void main(String[] args) {
chicken menu = chicken.sauce; // 열거형 상수에 접근 ( 열거형이름.상수명)
// menu에 chicken.sauce을 담음
chicken[] allchicken = chicken.values(); //열거형 자료에 정의된 상수들을 배열로 반환
for(chicken x : allchicken){
System.out.printf("%s = %d%n",x.name(), x.ordinal());
//name, ordinal 메서드 사용, 이름과 순서 반환
}
chicken findchicken = chicken.valueOf("onion");
// valueOf 메서드로 열거형에서 이름과 일치하는 열거형 상수 반환 상수가 의도한 상수랑 같은지 확인
System.out.println(findchicken);
System.out.println(chicken.onion == chicken.valueOf("onion"));
switch (menu){
case fried:
System.out.println("fried");
break;
case sauce:
System.out.println("sauce");
break;
case onion:
System.out.println("onion");
break;
}
}
}
//출력
fried = 0
sauce = 1
onion = 2
onion
true
sauce
여기서 참고해야 하는것은 열거형은 선얼 될 때 내부에 선언되는 상수에 0부터 정수값을 할당한다.
enum Seasons {
SPRING, //정수값 0 할당
SUMMER, //정수값 1 할당
FALL, //정수값 2 할당
WINTER //정수값 3 할당
}
또한 열거형에서 적용되는 메서드들이 있다.
String | name() | 열거 객체가 가지고 있는 문자열을 리턴하며, 리턴되는 문자열은 열거타입을 정의할 때 사용한 상수 이름과 동일합니다. |
int | ordinal() | 열거 객체의 순번(0부터 시작)을 리턴합니다. |
int | compareTo(비교값) | 주어진 매개값과 비교해서 순번 차이를 리턴합니다. |
열거 타입 |
valueOf(String name) | 주어진 문자열의 열거 객체를 리턴합니다. |
열거 배열 |
values() | 모든 열거 객체들을 배열로 리턴합니다. |
2. 제네릭
클래스를 이용해서 객체를 찍어 낼 때, 내부에 선언된 맴버에 따라 반환타입이 결정된다.
그렇기 때문에, 다른 타입의 반환을 가지고 싶으면 다른 타입으로 다시 클래스를 만들어 주어야 한다.
일반적인 클래스 예시
class Basket {
private String item;
Basket(String item) {
this.item = item;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
}
이 클래스를 String 말고 int로 반환하고 싶으면 또 바꿔서 만들고, double로 만들고싶으면 또또 새로 만들어야 한다는 것이다.
하지만, 제네릭을 이용하면 하나의 클래스 만드로 모든 타입의 데이터를 저장 할 수 있는 인스턴스를 만들 수 있다!
제네릭 이용 예시
class Basket<T> {
private T item;
public Basket(T item) {
this.item = item;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
위의 클래스 코드와 비교하면
- 클래스 이름 옆에 <T> 가 추가됨
- 변수타입(String) 대신에 T 를 넣음
을 볼 수 있다.
위의 제네릭을 이용한 클래스를 인스턴스화 할때는
Basket<String> basket1 = new Basket<String>("기타줄");
이와 같이 사용 가능하다.
위의 예시에서 클래스가 인스턴스화 될 때 클래스 이름 뒤에 <String>이 붙고 있는데, 이는 제네릭의 문법이다.
의미는 “Basket 클래스 내의 T를 String으로 바꿔라” 이다.
위의 코드에서 <String>으로 지정하였으니, 윗부분 "일반적인 클래스 예시" 처럼 T 가 모두 String으로 치환되어 동작한다.
만약 int형 자료로 사용하고 싶으면
Basket<Integer> basket1 = new Basket<Integer>(3);
String을 Integer 로 바꾸어서 인스턴스화 하면 된다.
" int로 안하고 Integer로 하는거는 뭔 차이냐?"
int는 기본 타입인데, Integer는 래퍼 클래스라고 한다.
래퍼 클래스를 쓰는 이유는 특정 이유로 단순 기본 타입이 아닌 객체 타입이 필요 할 때, 해당 데이터를 객체로 변환 해 주어야 정상작동 하기 때문이다.
고로 int 타입의 데이터 라기보다는 int타입의 객체 를 전달한거라고 생각하면 된다.
부가적으로, 기본 타입의 변수를 래퍼 클래스로 인스턴스화 하는것을 박싱(Boxing),
래퍼 클래스의 인스턴스 값을 다시 기본 타입으로 꺼내는 것을 언박싱 (UnBoxing) 이라고 한다.
"String 은 그냥 쓰고 왜 int만 바꾸냐?"
int 하고 char, boolean 타입이 래퍼클래스와 이름이 다르기 때문이다.
String은 기본형이 아니고, 사실 String 클래스의 객체를 만드는 방식으로 구현된다고 한다. (그래서 다른 데이터 타입과 다르게 참조형 데이터 타입을 가진다.)
그러니까, 사실 그동안 String타입의 기본 데이터를 넣어서 줫던게 아니고, 객체로 만들어서 줫던건데, 그냥 우리가 (혹은 나만 ㅎ) 몰랏던 것이다.
5주차 1일차는 아직 미완
컨디션 난조 + 집 정전으로 인해 작업불가
주말에 마저 쓸 예정
오늘은 5주차 2일차를 작성해야 되서 ㅠㅠ
순서가 꼬이니까 미리 올리고 수정 예정
아마 가능한한 빨리 해야겟다.
점점 후달린다 ㅋㅋㅋ
'백엔드 > 코드스테이츠 수강' 카테고리의 다른 글
코드스테이츠 수강_5주차_3~4일차_JAVA_심화(스레드, 자바 가상 머신) (0) | 2022.09.16 |
---|---|
코드스테이츠 수강_5주차_2일차_JAVA_심화(애너테이션, 람다, 스트림, 파일 입출력) (0) | 2022.09.15 |
코드스테이츠 수강_4주차_3~4일차_JAVA_객체지향 프로그래밍 심화(다형성, 추상화) (1) | 2022.09.07 |
코드스테이츠 수강_4주차_2일차_JAVA_객체지향 프로그래밍 심화 (상속, 캡슐화) (0) | 2022.09.06 |
코드스테이츠 수강_4주차_1일차_JAVA기초 (생성자, this,내부클래스) (0) | 2022.09.05 |