Spring 입문 주차 4일차
1. 지네릭스(Generics)
1)역할
- 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에서 컴파일 시 타입 체크를 해주는 기능
- 타입의 안정성을 제공한다
- 타입체크와 형변환을 생략할 수 있음으로 코드가 간결해 진다.
- 아래 코드에서 여러 종류의 타입을 저장하고 싶으면 <Object>로 사용하면 된다. 하지만 이 경우엔 출력시 형변환 필요 ArrayList<Object> list = new ArrayList<Object>();
ArrayList list = new ArrayList();
list.add(10);
list.add(20);
list.add("30");
Integer i =(Interger)list.get(2); //컴파일은 ok이나 실행시 ClassCastException 에러(형변환에러) 발생
//실행시 발생에러는 프로그램을 멈추게 함으로 같은 에러라면 컴파일 에러가 났다.
//즉 실행시 발생하는 에러를 컴파일에로 바꿔주기 위해(확인하기 위해) 사용되는 것이 Generics
ArrayList<Interger> list = new ArrayList();
list.add(10); // list.add(new Integer(10)); 알아서 boxing 해준 것
list.add(20);
list.add("30"); // 이 시점에서 컴파일러가 에러를 잡아준다. > list.add(30)으로 안바꾸면 실행 불가
Interger i = list.get(2); // 형변환 생략 가능
- < > 안에 들어가는 것을 타입변수 (type variable) 이라고 한다.일반적으로 T 나 E로 사용
2)타입 변수
- 형변환이 불필요한 성질과 이어진다. 보통 반환 타입이 Object이지만 지네릭스를 이용해 다양한 타입으로변환 가능
- <E> 또는 <T>로 타입 변수를 칭한다. E나 T는 Integer와 같은 특정 타입을 지칭하는게 아닌 예시이자 대명사를 뜻함
class Tv {}
class audio{}
////
ArrayList<Tv> list = new ArrayList<Tv>(); // TV타입의 저장 객체만 가능
list.add(new Tv());
list.add(new Audio()); //불가능
Tv t = list.get(0);
// 지네릭스 안주면
Tv t = (Tv)list.get(0);
3)지네릭스 타입과 다형성
- 참조 변수와 생성자의 대입된 타입(매개변수화된 타입, parameterized type)은 일치해야한다.
- 지네릭스 클리간에도 다형성은 성립, 매개변수의 다형성도 성립
ArrayList<TV> list = new ArrayList<Tv>(); // 참조변수와 생성자의 대입된 타입(=Tv) 일치
//지네릭 클래스간 다형성 성립
List<Tv> list = new ArrayList<Tv>();
List<Tv> list = new LinkedList<Tv>();
//매개변수의 다형성도 성립
ArrayList<Product> list = newArrayList<Product>();
list.add(new Product());
list.add(new Tv()); //OK
list.add(new Audio()); //OK
4)Iterator<E>
- 참조 변수와 생성자의 대입된 타입(매개변수화된 타입, parameterized type)은 일치해야한다.
- 지네릭스 클리간에도 다형성은 성립, 매개변수의 다형성도 성립
public interface Iterator<E> {
boolean hasNext();
next();
void remove();
}
Iterator<Student> it = list.iterator();
while(it.hasNext()){
Student s = it.next();// 지네릭스가 없다면 (Student)it.next(); 로 받환해야함
}
5)HashMap<K, V>
- 이 경우에도 예를 들면 Student라는 클래스로 V의 타입을 줬을 때 Value 반환시 형 변환 불필요
- ex)Student s1 = (Student)map.get("1-1"); // (Student) 생략 가능
6)제한된 지네릭 클래스
- extends를 이용하여 해당 클래스와 클래스의 자손만 들어갈 수 있게 해준다.
- 인터페이스를 같이 쓸때는 Fruit & Interfacename 과 같이 쓸 수 있다.
class FruitBox<T extends Fruit>{}
7)지네릭스의 제약
- static에 타입 변수 사용 불가 : static은 모든 인스턴스에 공통인데 타입 변수에 대입은 인스턴스 별로 다르게 가능하기 때문이다.
- 배열 생성할 때 타입 변수 사용 불가, 타입 변수로 배열 선언은 가능 => T나 E사용 불가 ex) new T 는 사용 불가
8)와일드 카드
- 하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능
- <? extends T> 와일드 카드의 상한 제한으로 T와 자손들만 가능
- <? super T> 와일드 카드의 하한제한, T와 그 조상들만 가능
- <?> 제한 없음, <? extends Object>와 동일
9)지네릭 메서드
- 지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유호), 대부분 생략 가능
static <T extends Fruit> Juice makeJucie(FruitBox<T> box)
//여기서 T에는 Fruit의 자손만 대입가능
10)지네릭 타입의 형 변환
- 지네릭 타입과 원시 타입간의 형변환은 바람직 하지 않다. 하지만 항상 가능
Box box = null;
Box<Object> objBox = null;
box = (Box)objBOx; //Ok. 지네릭타입> 원시타입, 경고발생
objbox = (Box<Object>)box; //Ok. 원시타입> 지네릭타입, 경고발생
- 대입된 타입이 다른 지네릭 타입 간에는 형변환이 불가능하다.
Box<Object> objBox = null;
Box<String> strBox = null;
objbox = (Box<Object>)strBox; //에러 Box<Stirng> -> Box<Object>
strbox = (Box<String>)objBox; //에러 Box<Object> -> Box<String>
- 와일드 카드가 사용된 지네릭 타입으로는 형변환 가능
Box<Object> objBox = (Box<Object>) new Box<String>(); // 에러 발생, 형변환 불가능
Box<? extends Object> wBox = (Box<? extends Object>) new Box<String>(); // OK
Box<? extends Object> wBox = new Box<String>();//Ok, 위 문장과 동일 생략 가능
11)지네릭 타입의 제거
- 컴파일러는 지네릭 타입을 제거하고, 필요한 곳에 형변환을 넣는다.
- 지네릭 타입의 경계(bound)를 제거, 하위호환성// 지네릭은 컴파일 수준에서만 존재하여 하위 버전에서 구동 가능 (자바의 특징이다)
- 지네릭 타입을 제거한 후에 타입이 일치하지 않으면 형변환을 추가한다.
2. 열거형(enum)
1) 기초
- 여러 상수를 선얼 할 때 편리하게 사용하는 방법, 아래 방법이 아니라면 하나한 0,1,2,3... 값을 지정해 주어야 함
class Card{
enum Kind {CLOVER,HEART,DIAMOND,SPADE} // 순서대로 0,1,2,3 부여
enum Value {TWO,THREE,FOUR} // 마찬가지로 0,1,2 부여
final Kind kind;
final Value value;
}
- 타입은 int 가 아닌 Kind와 Value 처럼 선언 할 때와 같은 형태로 주어야 한다.
- 조건식에서 type을 먼저 비교하게 함으로써 컴파일 단계에서 에러를 도출하여 미리 예방한다.
if(Card.CLOVER == Card.TOW) /// true이지만 false이어야 의미가 맞음
if(Card.Kind.CLOVER == Card.Value.TOW) /// type부터 비교하여 컴파일에러 발생
2)열거형의 정의와 사용
- 정의하는 방법 : enum 열거형이름 {상수명1,상수명2, .....}
- 열거형 타입의 변수를 선언하고 사용하는 방법
enum Direction {EAST, SOUTH, WEST, NORTH}
class Unit{
int x, y;
Driction dir;
void init() {
dir = Direction.EAST;
}
}
- 열거형 상수의 비교에는 == 와 compartTo() 사용 가능, [<,>] 같은 비교 연산자 사용 불가
- compareTo(), 왼쪽이 크면 양수, 같으면 0, 오른쪽이 크면 음수를 반환
3)열거형의 조상- java.lang.Enum
- 모든 열거형은 Enum의 자손이며, 아래의 메서드를 상속받는다.
- Class<E> getDeclaringClass() : 열거형의 Class 객체를 반환
- String name() : 열거형 상수의 이름을 문자열로 반환
- int ordinal() : 열거형 상수가 정의된 순서를 반환(0부터 시작)
- T valueOf(Class<T> enumType, String name) : 지정된 열거형에서 name과 일치하는 열거형 상수를 반환
- 조상엔 없지만 자동으로 추가해 주는 메서드
- values() : 열거형에 정의된 모든 상수를 출력하는데 사용 ex) Direction darr = Direction.values();
- valuseOf(String name) : 열거형 상수의 이름을 문자열 상수에 대한 차조를 얻을 수 있게 해준다.
4)열거형에 멤버 추가하기
- 불연속적인 열거형 상수의 경우 원하는 값을 괄호안에 적는다. 여러개도 가능 ex) EAST(1, ">")
- 값을 호출하려면 생성자가 필요하기 때문에 아래와 같이 사용하게 된다.
enum Direction {
EAST(1), SOUTH(5),WEST(-1),NORTH(10);
private final int value;
Dirention(int value) {this.value = value;}
public int getValue() { return value;}
}
3. 에너테이션(annotation)
1) 에너테이션이란?
- 과거 소스코드와 문서를 하나의 파일로저장하려고 하였으며, @붙은 태그를 이용하여 주석안에 정보를 저장 하고 , javadoc.exe라는 프로그램이 이 정보를 읽어서 문서 작성하는데 사용한다. 이 기능을 응용하여, 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이 바로 애너테이션
- 애너테이션은 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유요한 정보를 제공한다.
- JDK에서 제공하는 표준 애너테이션은 주로 컴파일러를 위한 것으로 컴파일러에게 유용한 정보를 제공한다.
- @Override
- @Deprecated
- @SuppressWarnings
- @SafeVarargs
- @FunctionalInterface
- @Native
2)애너테이션 타입 정의하기
@interface 애너테이션이름 {
타입 요소이름(); //애너테이션의 요소를 선언한다.
........
}
- 애너테이션 요소는 반환값이 있고 매개변수는 없는 추상 매서드의 형태를 가지며, 상속을 통해 구현하지 않아도 된다.
- 요소형의 타입은 기본형, String, enum, 애너테이션, Class 만 허용
- ()안에 매개변수를 선언 할 수 없다.
- 예외를 선언할 수 없다.
- 요소를 타입 매개변수로 정의할 수 없다.
4. 참고 자료
1)API 공통 응답 포맨 개발
https://velog.io/@wwe221/ApiReponse
https://hyuckang.tistory.com/68
2)예외 처리 https://velog.io/@dbsrud11/Spring-MVC-2-9.-API-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC