Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 코드로 시작하는 자바 첫걸음
- 스프링 db2 - 데이터 접근 기술
- 스프링 mvc2 - 로그인 처리
- 2024 정보처리기사 시나공 필기
- 자바의 정석 기초편 ch9
- 스프링 입문(무료)
- 스프링 mvc2 - 검증
- 자바의 정석 기초편 ch8
- 자바의 정석 기초편 ch3
- 자바의 정석 기초편 ch5
- 자바의 정석 기초편 ch13
- 스프링 mvc1 - 스프링 mvc
- 스프링 고급 - 스프링 aop
- 스프링 mvc2 - 타임리프
- 타임리프 - 기본기능
- 자바의 정석 기초편 ch2
- 자바의 정석 기초편 ch1
- 자바의 정석 기초편 ch6
- jpa 활용2 - api 개발 고급
- 자바의 정석 기초편 ch12
- 게시글 목록 api
- 자바의 정석 기초편 ch7
- @Aspect
- 자바의 정석 기초편 ch14
- 2024 정보처리기사 수제비 실기
- jpa - 객체지향 쿼리 언어
- 자바의 정석 기초편 ch11
- 스프링 db1 - 스프링과 문제 해결
- 스프링 mvc1 - 서블릿
- 자바의 정석 기초편 ch4
Archives
- Today
- Total
나구리의 개발공부기록
자바의 정석 기초편 ch12 - 15 ~ 22 [제네릭형변환, 열거형, 열거형의 조상, 열거형에 멤버 추가하기] 본문
유튜브 공부/JAVA의 정석 기초편(유튜브)
자바의 정석 기초편 ch12 - 15 ~ 22 [제네릭형변환, 열거형, 열거형의 조상, 열거형에 멤버 추가하기]
소소한나구리 2023. 12. 14. 10:411) 제네릭타입의 형변환
- 제네릭타입과 원시 타입간의 형변환은 바람직 하지 않음 (가능 하지만 경고 발생)
- JDK1.5 이후부터는 원시타입을 쓰는 것 자체가 바람직 하지 않으며 서로 다른타입이 대입된 제네릭타입은 형변환이 불가함
- 와일드카드가 사용된 제네릭 타입으로는 형변환 가능하며 와일드카드 문장에 따라 달라지며 경고가 발생할 수 있음
(1) 예시
Box<Object> objBox = null;
Box box = (Box)Box<Object>; // OK. 제네릭타입 -> 원시타입 / 경고 발생
objbox = (Box<Object>)Box; // OK. 원시타입 -> 제네릭타입 / 경고 발생
Box<Object> objBox = null;
Box<String> strBox = null;
objBox = (Box<Object>)strBox; //에러. 서로 다른타입이 대입된 제네릭타입끼리의 형변환 불가
strBox = (Box<String>)objBox; //에러.
// 와일드 카드가 사용된 제네릭타입으로의 형변환은 가능
// Object와 그의 자손들 사용 가능
Box<? extends Object> wBox = (Box<? extends Object>)new Box<String>(); // OK
Box<? extends Object> wBox = new Box<String>(); //위 문장과 동일(형변환 생략)
// 와일드 카드가 사용된 제네릭스 클래스 참조변수로 형변환
FruitBox<? extends Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<? extends Fruit> appleBox = new FruitBox<Apple>();
// 와일드 카드를 사용된 제네릭스 클래스 참조변수를 형변환
FruitBox<Apple> appleBox2 = (FruitBox<Apple>)appleBox; // OK. 경고 발생
2) 제네릭 타입의 제거
- 컴파일러는 제네릭 타입을 제거한 뒤에 필요한 곳에 형변환을 넣음(하위 호환성 때문에 이렇게 작동함)
- C#언어는 컴파일 때 제네릭타입을 유지 (사실 유지하는 것이 더 유리함 - 성능, 런타임때 제네릭 확인 등등)
(1) 컴파일 시 제네릭 타입이 제거되는 과정
- 1. 제네릭 타입의 경계(bound)를 제거
- 2. 제네릭 타입 제거 후에 타입이 불일치(형변환이 생략되어 있을 때)하면, 형변환을 추가
- 와일드 카드가 포함된 경우, 적절한 타입으로 알아서 형변환을 추가
3) 열거형(enum)
- 서로 관련된 상수들을 같이 묶어 놓은 것
- 정의한 순서대로 번호가 0부터 자동으로 부여 됨
- C언어는 값만 체크하는 것에 비해 Java는 값과 타입을 모두 체크하므로 타입에러에 안전한 열거형을 제공함
if(Card.kind.CLOVER==Card.Value.TWO) { //컴파일에러 - 타입이 달라서 비교 불가
(1) 열거형의 정의와 사용
- 열거형을 정의하고 사용하는 방법
// enum 열거형이름 { 상수명1, 상수명2, ... } 으로 정의
enum Direction { EAST, SOUTH, WEST, NORTH}
// enum 사용
class Unit {
int x, y;
Direction dir; // 열거형 타입의 변수를 선언
void init() {
dir = Direction.EAST; // init 메서드 호출 시 열거형의 EAST를 참조변수에 저장
}
}
(2) 열거형 상수 비교
- == 와 compareTo()사용 가능하며 비교연산자(>, < 등)는 사용 불가
- compareTo(): 비교 값이 같으면 0, 왼쪽의 갑이 크면 양수, 오른쪽의 값이 크면 음수
(3) 열거형의 조상 - java.lang.Enum(클래스)
- 모든 열거형은 Enum의 자손으로 메서드를 상속 받음
- ordinal()은 상수가 정의된 순서이지 상수가 정의된 값과는 무관함
(4) 메서드
- Class<E> getDeclaringClass() : 열거형의 Class 객체를 반환함
- String name() : 열거형 상수의 이름을 문자열로 반환함
- int ordinal() : 열거형 상수가 정의된 순서를 반환함(0부터 시작)
- T valueOf(Class<T> enumType, String name): 지정된 열거형에서 name과 일치하는 열거형 상수를 반환함
- T[] : values() : 정의한 모든 상수를 배열로 반환함
- values(), valuesOf()는 컴파일러가 자동으로 추가해줌
//values(): 가지고있는 모든 상수를 배열로 반환함
Direction[] dArr = Direction.values();
// 이름과 순서를 for문으로 출력
for(Direction d : dArr)
System.out.printf("%s=%d%n", d.name(), d.ordinal());
//ValuesOf사용 예
Direction d = Direction.valueOf("WEST"); // 열거형 상수를 d에 저장
Direction d = Direction.WEST // 위와 동일함
(5) 예제
// 0 1 2 3
enum Direction { EAST, SOUTH, WEST, NORTH } // 열거형 상수는 기본형이 아니라 객체
class Ex12_5 {
public static void main(String[] args) {
// 열거형 상수를 저장하는 여러 방법
Direction d1 = Direction.EAST; // 열거형타입.상수이름
Direction d2 = Direction.valueOf("WEST"); //문자열 이용
Direction d3 = Enum.valueOf(Direction.class, "EAST"); // 최고조상의 valueOf를 이용
System.out.println("d1="+d1);
System.out.println("d2="+d2);
System.out.println("d3="+d3);
System.out.println("d1==d2 ? "+ (d1==d2));
System.out.println("d1==d3 ? "+ (d1==d3));
System.out.println("d1.equals(d3) ? "+ d1.equals(d3)); // 객체라서 equals 사용 가능
// System.out.println("d2 > d3 ? "+ (d1 > d3)); // 에러. 비교연산자사용 불가(객체라서)
System.out.println("d1.compareTo(d3) ? "+ (d1.compareTo(d3)));
System.out.println("d1.compareTo(d2) ? "+ (d1.compareTo(d2)));
switch(d1) {
case EAST: // Direction.EAST라고 쓰지않고 상수만 입력 - case문의 문법임
System.out.println("The direction is EAST."); break;
case SOUTH:
System.out.println("The direction is SOUTH."); break;
case WEST:
System.out.println("The direction is WEST."); break;
case NORTH:
System.out.println("The direction is NORTH."); break;
default:
System.out.println("Invalid direction."); break;
}
// 열거형의 모든 상수를 배열로 반환
Direction[] dArr = Direction.values();
for(Direction d : dArr) // for(Direction d : Direction.values())
System.out.printf("%s=%d%n", d.name(), d.ordinal());
}
}
/*
출력값
d1=EAST
d2=WEST
d3=EAST
d1==d2 ? false
d1==d3 ? true
d1.equals(d3) ? true
d1.compareTo(d3) ? 0
d1.compareTo(d2) ? -2
The direction is EAST.
EAST=0
SOUTH=1
WEST=2
NORTH=3
*/
4) 열거형에 멤버 추가하기
- 불연속적인 열거형 상수의 경우 원하는 값을 상수의 괄호() 안에 작성하여 멤버를 추가할 수 있음
- 개수와 타입의 제한이 없이 입력할 수 있음
// 정의된 순서는 0,1,2,3
enum Direction { EAST(1, ">"), SOUTH(5), WEST(-1), NORTH(10)}
(1) 괄호()를 사용하려면 인스턴스 변수와 생성자가 필요함
- 열거형의 각 상수에 정의된 멤버를 사용하기 위해서는 변수를 선언하여 생성자로 변수에 값을 입력하는 방식으로 사용해야함
- 열거형의 생성자는 묵시적으로 private이므로 외부에서 객체 생성이 불가능함
(2) 예제
- name(): 정의된 상수의 이름을 출력
- getValue(), getSymbol() : 상수의 멤버를 출력할 수 있도록 메서드를 작성
enum Direction2 { // 열거형 선언
EAST(1, ">"), SOUTH(2,"V"), WEST(3, "<"), NORTH(4,"^");
private static final Direction2[] DIR_ARR = Direction2.values();
private final int value; // 첫번째 값 저장
private final String symbol; // 두번째 값 저장
// 생성자 생성
Direction2(int value, String symbol) { // 접근 제어자 private이 생략됨
this.value = value;
this.symbol = symbol;
}
public int getValue() { return value; }
public String getSymbol() { return symbol; }
public static Direction2 of(int dir) {
if (dir < 1 || dir > 4) // 0 ~ 3범위가 벗어나면 예외가 발생하도록 작성
throw new IllegalArgumentException("Invalid value :" + dir);
return DIR_ARR[dir - 1];
}
// 방향을 회전시키는 메서드. num의 값만큼 90도씩 시계방향으로 회전
public Direction2 rotate(int num) {
num = num % 4; // 큰값을 입력하여도 회전
if(num < 0) num +=4; // num이 음수일 때는 시계반대 방향으로 회전
return DIR_ARR[(value-1+num) % 4];
}
public String toString() {
return name()+getSymbol();
}
} // enum Direction2
class Ex12_6 {
public static void main(String[] args) {
for(Direction2 d : Direction2.values())
//ordinal로 하면 입력된 순서가 출력
System.out.printf("%s=%d%n", d.name(), d.getValue()); // 상수의 값을 출력
Direction2 d1 = Direction2.EAST;
Direction2 d2 = Direction2.of(2);
System.out.printf("d1=%s, %d%n", d1.name(), d1.getValue());
System.out.printf("d2=%s, %d%n", d2.name(), d2.getValue());
System.out.println(Direction2.EAST.rotate(1));
System.out.println(Direction2.EAST.rotate(2));
System.out.println(Direction2.EAST.rotate(-1));
System.out.println(Direction2.EAST.rotate(-2));
}
}
/*
출력값
EAST=1
SOUTH=2
WEST=3
NORTH=4
d1=EAST, 1
d2=SOUTH, 2
SOUTHV
WEST<
NORTH^
WEST<
*/
** 출처 : 남궁성의 정석코딩_자바의정석_기초편 유튜브 강의