Java/Java의 정석

Chapter 12 지네릭스, 열거형, 에너테이션

계란💕 2022. 3. 2. 23:42

1. 지네릭스(Generics)

  1.1 지네릭스란?

  Def) 지네릭스: 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크를 해주는 기능

  - 자료형을 제한해주는 기능이다.

  - 타입 안정성이 높아지고 형변환의 번거로움이 줄어들어 간결해진다.

  - 의도하지 않은 타입의 객체가 저장되는 것을 막는다.

                                                                                                 

  1.2 지네릭 클래스의 선언

  - 클래스메서드에 선언할 수 있다. 

  Ex) 지네릭 클래스 Box가 선언되어 있을 때

  - Box<T>: 지네릭 클래스, 'T의  Box' 또는 'T Box'라고 있는다.

  - T: 타입 변수 또는 타입 매개변수(T는 타입 문자)

  - Box: 원시 타입(raw type)

 

  Note) 지네릭스의 제한

  - 지네릭 타입의 배열을 생성할 수 없다.

  - static 멤버에 타입 변수 T를 사용할 수 없다.

 

  1.3 지네릭 클래스의 객체 생성과 사용

  Ex)

java
열기

  Note) 실행결과

  - appleBox.add(new toy()); 에러 -> Box<Apple>에는 Apple만 담을 수 있다.

  - Grape, Apple은 Fruit의 자손이므로 상속 관계에 있다. 

    -> fruitBox에 Apple을 추가할 수 있다.

 

   1.4 제한된 지네릭 클래스

  - 지네릭 타입에 'extends'를 사용하면 특정 타입의 자손들만 대입할 수 있도록 제한한다.

  - 타입 매개 변수 T에 Object를 대입하면 모든 종류의 객체를 저장 가능하다.

  Ex)

java
열기

  Note) 실행결과

  - implements가 아닌 'extends'를 이용해서 Eatable인터페이스를 구현한다. 

 

  1.5 와일드카드

c++
닫기
<? extends T> : 와일드 카드의 상한 제한. T와 그 자손들만 가능
<? super T> : 와일드 카드의 하한 제한. T와 그 조상들만 가능
<?> : 제한 없음. 모든 타입이 가능하다.  < ? extends Object >와 동일하다.

   

  Ex)

c++
열기

  Note) 실행결과

  - Collections.sort()를 이용해서 appleBox와 grapeBox에 담긴 과일을 무게 별로 정렬한다.

  - Comparator<? super apple>: Comparator의 타입 매개변수로 Apple과 그 조상이 가능하다는 뜻.

 

  1.6 지네릭 메서드

  - 지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)

    -> 반환 타입 바로 앞에 지네릭 타입을 선언한다.

  - 클래스의 타입 매개변수 <T>와 메서드의 타입 매개변수 <T>는 별개

  - 메서드를 호출할 때마다 타입을 대입해야 (대부분 생략 가능)

  - 메서드를 호출할 때, 타입을 생략하지 않을 때는 클래스 이름 생략 불가

  1) 타입 T를 요소로 하는 List를 매개변수로 허용한다.

  2) 'T'는 Comparable을 구현한 클래스여야 한다.( <T extends Comparable> )

    -> 'T'또는 그 조상의 타입을 비교하는 Comparable이어야한다는 것( Comparable<? super T>)를 의미

    -> T가 Student이고 Person의 자손이라면 <? super T>는 Student, Person, Object가 모두 가능하다.

 

  1.7 지네릭 타입의 형변환

  - 지네릭 타입과 원시 타입(raw type) 간의 형변환은 바람직하지 않다. (경고 발생)

  - 대입된 타입이 다른 지네릭 타입 간에는 형변환이 불가능하다.

  - 와일드 카드가 사용된 지네릭 타입끼리도 형변환 가능한 경우가 있다. (경고 발생)

 

  1.8 지네릭 타입의 제거

  - 컴파일러는 지네릭 타입을 제거하고 필요한 곳에 형변환을 넣는다.

  - 제거 과정

  1) 지네릭 타입의 경계(Bound)를 제거

  2) 지네릭 타입 제거 후에 타입이 불일치하면, 형변환을 추가한다.

    -> 와일드 카드가 포함된 경우, 적절한 타입으로 형변환 추가한다. 

 

2. 열거형(enums)

  2.1 열거형이란?

  Def) 열거형: 관련된 상수들을 같이 묶어 놓은 것. Java는 타입에 안전한 열거형을 제공한다.

  

  2.2 열거형의 정의와 사용

  - 열거형 정의: enum 열거형이름 { 상수명1, 상수명2, ... }

  - 열거형 타입의 변수를 선언하고 사용하는 방법

  - 열거형 상수의 비교에 '==' 와 compareTo() 사용 가능하다. (부등호는 사용불가)

    -> compareTo() : 같으면 0 / 왼쪽이 크면 (+) / 오른쪽이 크면 (-) 반환

  - 모든 열거형의 조상 - java.lang.Enum

    -> values(), valueOf()는 컴파일러가 자동으로 추가

    -> values():열거형의 모든 상수를 배열에 담아 반환한다. 

  Ex)

c++
열기

  Note) 실행결과

 

  2.3 열거형에 멤버 추가하기

  - ordinal()이 열거형 상수가 정의된 순서를 반환하지만 사용하지 않는 게 좋다.

  - 불연속적인 열거형 상수의 경우, 원하는 값을 괄호()안에 적는다.

  - 정수를 저장한 필드(인스턴스 변수)를 추가해야한다.

  - 열거형의 생성자는 묵시적으로 private이므로 외부에서 객체 생성 불가.

  - 열거형의 생성자는 외부에서 호출 불가능

 

 

  Ex)

c++
열기

  Note) 실행결과

  - 하나의 열거형 상수여러 값을 지정할 수 있다. 

  - rotate(): 방향을 회전시키는 메서드, num의 값만큼 90도씩 시계 방향으로 회전한다.

   -> num이 음수일 때는 시계 반대 방향으로 회전한다.

 

  2.4 열거형의 이해

  - 열거형 상수 하나 하나가 Direction객체이다.

  - Direction클래스의 static상수 EAST, SOUTH, WEST, NORTH 값은 객체의 주소이다.

    -> 이 값은 바뀌지 않으므로 == 로 비교가 가능하다.

    -> 객체가 생성될 때마다 번호를 붙여서 인스턴스변수 ordinal에 저장한다. 

 

  Ex) 컴파일 에러 발생하는데 오류는 

c++
열기

  Note) 실행결과

  - 열거형에 추상 메서드를 추가하면 각 열거형 상수가 추상 메서드를 구현해야한다.

  

 

3. 애너테이션(annotation)

 

  3.1 애너테이션이란?

  Def) 애너테이션: 프로그램의 소스 코드안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이다.

  • 주석처럼 프로그래밍 언어에 영향을 미치지 않으며 유용한 정보를 제공

 

  3.2 표준 애너테이션

  - Java에서 제공하는 애너테이션

  - @Override: 오버라이딩을 바르게 했는지 컴파일러가 체크하도록 한다.

    -> 오버라이딩할 때 메서드 이름을 잘못 적는 실수를 하는 경우가 많다.

    -> 메서드 선언부 앞에 붙인다.

  - @Deprecated: 앞으로 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다.

    ex) Date클래스의 getDate()

   - @FunctionalInterface: 함수형 인터페이스에 붙이면 컴파일러가 올바르게 작성했는지 체크

    -> 함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있다.

   - @SuppressWarnings: 컴파일러의 경고 메시지가 나타나지 않게 억제한다.

    -> 괄호() 안에 억제하고자한는 경고의 종류를 문자열로 지정

    -> 둘 이상의 경고를 동시에 억제하려면 괄호 안에 쭉 쓴다.

    -> 'Xlint'옵션으로 컴파일하면 경고메시지를 확인할 수 있다.

  - @SafeVarargs: 메서드에 선언된 가변인자 타입이 non-refiable 타입일 경우, 해당 메서드를 선언하는 부분과 호출하는 부분에서 "unchecked" 경고가 발생한다. 해당 코드에 문제가 없다면 경고를 억제시키기 위해 사용한다.

    -> @SafeVarargs로 "unchecked"는 억제할 수 있지만 "varargs"경고는 억제할 수 없기 때문에 

    -> @SuppressWarnings("varargs")를 같이 붙인다.

 

 

  3.3 메타 애너테이션

  - 메타 애너테이션은 '애너테이션을 위한 애너테이션'

  - 애너테이션의 적용 대상이나 유지 지간을 지정하는데 사용한다. 

  - @Target: 애너테이션을 정의할 때, 적용 대상 지정에 사용

    -> TYPE: 타입을 선언할 때, 애너테이션을 붙일 수 있다.

    -> TYPE_USE: 해당 타입의 변수를 선언할 때 붙일 수 있다.

  - @Retention: 애너테이션이 유지되는 기간을 지정하는데 사용

    -> 컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE이다.

    -> 실행 시에 사용가능한 애너테이션의 정책은 RUNTIME이다.

   - @Documented: javadoc으로 작성한 문서에 포함시키려면 붙인다.

  - @Inherited: 에너태이션을 자손 클래스에 상속하고자 할 때 붙인다.

    -> 조상 클래스에 붙이면 자손 클래스도 붙인 것처럼 인식된다. 

  - @Repeatable: 반복해서 붙일 수 있는 애너테이션을 정의할 때 사용

    -> @Todo를 하나로 묶을 컨테이너 애너테이션도 정의해야한다.

  - @Native: 네이티브 메서드에 의해 참조되는 상수 필드에 붙이는 애너테이션이다.

  

 

  3.4 애너테이션 타입 정의하기

  - 애너테이션의 메서드는 추상 메서드이며 애너테이션을 적용할 때 지정한다. (순서 X)

  - 에너테이션의 요소

    -> 반환값이 있고 매개변수를 없는 추상메서드의 형태를 가진다.

    -> 적용시 값은 지정하지 않으면, 사용될 수 있는 기본값 지정 가능(Null 제외)

    -> 요소가 하나이고 이름이 value일 때, 요소의 이름 생략가능하다.

    ->  요소의 타입이 배열인 경우, 괄호{}를 사용한다. (값이 하나일 때는 생략 가능, 값이 없을 때는 빈 괄호)

  

  - 모든 애너테이션의 조상

    -> Annotation은 모든 애너테이션의 조상이지만 상속은 불가하다.

    -> 사실 Annotation은 인터페이스이다. 

 

  - java.lang.annotation.Annotation

    - 마커 애너테이션: 요소가 하나도 정의되지 않은 애너테이션

    - 애너테이션 요소의 규칙

    1) 요소의 타입은 기본형, String, enum, 애너테이션, class만 허용된다.

    2) 괄호 안에 매개 변수를 선언할 수 없다.

    3) 예외를 선언할 수 없다.

    4) 요소를 타입 매개 변수로 정의할 수 없다.

 

 

  Ex) AnnoEx5

java
열기

  Note) 실행결과

  • getAnnotation(): 매개 변수로  정보를 얻는다.
  • getAnnotations(): 모든 애너테이션을 배열로 받아온다