이 글은 남궁성 님의 Java의 정석 책을 바탕으로 정리한 글입니다.
지네릭스
타입을 구체적으로 지정하는 것이 아니라, 추후에 지정할 수 있도록 일반화 해 둔다
1. 컴파일 시 타입 체크
2. 타입의 안정성을 제공하고, 형변환을 생략할 수 있으므로(무조건 명시한 타입일 테니까) 코드가 간결해짐
3. 클래스 변수(static)에는 타입 매개변수 사용 불가 : 공간을 공유하는 특성에 모순이 된다
ArrayList<Food> foodList = new ArrayList<Food>();
foodList.add(new Food());
//foodList.add(new Animal()); Error
Arraylist list = new Arraylist();
list.add(10); //Integer
list.add("20"); //String
Integer i = (Integer)list.get(1); //컴파일 OK, But 형변환 에러 발생 → 컴파일러의 한계
래퍼 클래스: 기본 타입 데이터를 객체로 표현해야 하는 경우에 사용하는 클래스를 말한다 (박싱)
→ Byte, Characher, Integer, Float, Double, Boolean, Long, Short
타입 변수와 다형성
1. 지네릭 클래스 작성 시 Object 타입 대신 타입 변수(T, K, V, E, N, R 등)를 선언
2. 객체 생성 시에는 실제 타입으로 선언한다!!! (래퍼 클래스)
3. 타입 변수 자리에 객체의 타입이 대입됨!
// 일반 클래스에서 지네릭 클래스로 변경, Object를 모두 "T"로 명시
class Box<E> {
E item;
void setItem(E item) { this.item = item; }
E getItem() { return item; }
}
객체 생성
타입 변수 대신 실제 타입을 대입한다
참조 변수 타입 = 생성자 대입 타입 같아야 함 (조상-자손 관계여도 안 됨 무조건 같아야 함)
타입 변수에 적용 시 다형성의 원리가 적용된다
ArrayList<Tv> list = new ArrayList<Tv>();
//지네릭스를 적용하기 이전에는?
ArrayList list = new ArrayList();
list.add(new Tv());
Tv t = (Tv)list.get(0); //형변환이 필요했다
제한된 지네릭 클래스
클래스 Fruit과 인터페이스 Eatable의 자손만 타입으로 지정 가능
1. 상속이나 인터페이스를 단독으로 나타낼 땐 extends 사용
2. 상속을 받으면서 + 인스페이스를 구현한 클래스를 나타낼 땐 &
class FruitBox<T extends Fruit & Eatable> { ... }
지네릭 메서드
클래스가 아닌 특정 메서드만 지네릭으로 선언 가능!
1. 지네릭 타입 결정 시기: 클래스는 인스턴스화 될 때, 메서드는 호출될 때
2. static 메서드에서도 사용 가능하다
3. 타입 지정 이전에는 어떤 타입인지 모르니 String의 length() 등은 사용 불가하다
Object는 모든 클래스의 조상이므로 Object의 메서드는 사용 가능함
class Basket<T> { //여기에서 선언한 타입 매개변수 T와
...
public <T> void add(T element) { //여기에서 선언한 타입 매개변수 T는 서로 다르다
...
}
}
와일드 카드<?>
하나의 참조 변수로 대임된 타입이 다른 객체를 참조 가능
메서드의 매개변수에 와일드 카드를 사용
<? extends T> 와일드 카드의 상한 제한, T와 그 자손들만 가능
<? super T> 와일드 카드의 하한 제한, T와 그 조상들만 가능
<?> 제한 없음, 모든 타입이 가능, <? extends Object>와 동일
static Juice makeJuice(FruitBox<? extends Fruit> box) {
// . . .
}
지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
static <T extends Fruit> Juice makeJuice(FruitBox<T> box) {
// . . .
}
지네릭 메서드: 메서드를 호출할 때마다 다른 지네릭 타입을 대입할 수 있게 한 것
와일드 카드: 하나의 참조 변수로 서로 다른 타입이 대입된 여러 지네릭 객체를 다루기 위한 것
지네릭 타입과 형변환
1. 지네릭 타입과 넌지네릭 타입
가능하지만 경고, 바람직하지 않다
box = (Box)objBox;
objBox = (Box<object>)box;
2. 대입된 타입이 다른 지네릭 타입 간의 변환
불가능
// objBox = (Box<Object>)strBox;
// strBox = (Box<String>)objBox;
3. Box<String>과 Box<? extends Object>
양쪽 모두 가능
열거형(enum)
관련된 상수들을 같이 묶어 놓은 것
1. 상수명 중복 방지
2. 타입 안정성
3. switch문에 적용 가능
enum Seasons { SPRING, SUMMER, FALL, WINTER }
//static 변수의 참조처럼 Seasons.SPRING으로 참조 가능
애너테이션
주석처럼 프로그래밍 언어에 영향을 미치지 않으며, 사람이 아니라 프로그램에게 유용한 정보를 제공
1. 컴파일러에게 문법 에러를 체크하도록
2. 빌드 시 코드를 자동으로 생성할 수 있도록
3. 런타임에 특정 기능을 실행하도록
표준 애너테이션
@Override | 오버라이딩을 올바르게 했는지 컴파일러가 체크하게 한다 (메서드 이름 작성 오류 등) |
@Deprecated | 앞으로 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다 (호환성 문제 등) |
@FuncionalInterface | 함수형 인터페이스 선언 시 올바르게 작성했는지 체크 - 추상 메서드가 2개 이상일 때 (함수형 인터페이스: 하나의 추상 메서드만 가져야 한다) |
@SuppressWarnings | 컴파일러의 경고 메시지가 나타나지 않게 억제한다 괄호() 안에 억제하고자 하는 경고의 종류를 문자열로 지정 발생하는 경고를 확인(체크)하였다는 표시, 새로운 문제 발생 시에도 인지하기 쉽다 |
<@SuppressWarnings>
all : 모든 경고 억제
deprecation: Deprecated 메서드를 사용한 경우 나오는 경고 억제
fallthrough : switch문의 break문 구문이 없을 때 ~
finally
null
uncheched : 검증되지 않은 연산자
unused : 사용하지 않는 코드
메타 애너테이션(애너테이션을 만들 때 사용)
애너테이션에 붙이는 애너테이션, 적용 대상과 유지 기간 등 정의
@Target | 애너테이션을 정의할 때, 적용 대상 지정 |
@Retention | 애너테이션이 유지되는 기간을 지정하는 데 사용 SOURCE : .java 소스 파일까지 CLASS : .class 파일까지 RUNTIME : 런타임 실행 시까지 |
@Documentec | javadoc으로 작성한 문서(*.html)에 포함시킬 때 |
@Inherited | 애너테이션을 자손 클래스에 상속하고자 할 때 |
@Repeatable | 반복해서 붙일 수 있는 애너테이션을 정의할 때 사용 하나로 묶을 컨테이너 애너테이션도 정의해야 한다 |
<@Target>
열거형으로 java.lang.annotation.ElementType에 정의되어 있다
ANNOTATION_TYPE : 애너테이션
CONSTRUCTOR
FIELD : 필드(멤버 변수, 열거형 상수)
LOCAL_VARIABLE
METHOD
PACKAGE
PARAMETER
TYPE : 타입(클래스, 인터페이스, 열거형)
TYPE_PARAMETER
TYPE_USE : 타입이 사용되는 모든 대상
애너테이션 타입 정의하기
애너테이션의 메서드는 추상 메서드이며, 애너테이션을 적용할 때 지정한다
'Back-End > Java' 카테고리의 다른 글
배열 문제 풀이 (0) | 2022.07.06 |
---|---|
조건문과 반복문 문제 풀이 (0) | 2022.07.05 |
컬렉션 프레임웍 (0) | 2021.12.30 |
예외 처리(exception handling) (0) | 2021.12.26 |
객체지향 프로그래밍 Ⅱ (0) | 2021.12.16 |
댓글