Generics
다양한 타입의 객체들을 다루는 메서드나 컬랙션 클래스에 컴파일 시 타입체크를 해주는 기능으로, 객체의 타입을 컴파일 시 체크하기 때문에 객체의 타입 안정성을 높이고, 형 변환의 번거로움이 줄어듭니다.
class Box<T> {}
Box<T> : 제네릭 클래스, T의 Box또는 T Box라고 읽습니다.
T : 타입 변수 또는 타입 매개변수
Box : 원시 타입
지네릭스의 제한
- static멤버에 타입 변수 T를 사용할 수 없습니다 -> T는 인스턴스 변수로 간주되기 때문입니다. static멤버는 인스턴스 변수를 참조할 수 없습니다. static멤버는 타입 변수에 지정된 타입, 즉 대입된 타입의 종류에 관계없이 동일한 것이어야하기 때문입니다.
- 지네릭 타입의 배열을 생성하는 것도 허용되지 않습니다 -> 컴파일 시점에 타입 T가 무엇인지 정확히 알아야 하기 때문입니다.
지네릭 타입의 객체 생성과 사용
package ch12;
import java.util.ArrayList;
class Fruit { public String toString(){return "Fruit";}}
class Apple extends Fruit{public String toString(){return "Apple";}}
class Grape extends Fruit{public String toString(){return "Grape";}}
class Toy {public String toString(){return "Toy";}}
public class FruitBoxEx1 {
public static void main(String[] args) {
Box<Fruit> fruitBox = new Box<Fruit>();
Box<Apple> appleBox = new Box<Apple>();
Box<Toy> toyBox = new Box<Toy>();
//Box<Grape> grapeBox = new Box<Apple>(); //에러 타입 불 일치
fruitBox.add(new Fruit());
fruitBox.add(new Apple()); // OK
appleBox.add(new Apple());
appleBox.add(new Apple());
//appleBox.add(new Toy()); // 에러. Box<Apple>에는 Apple만 담을 수 있다.
toyBox.add(new Toy());
//toyBox.add(new Apple()); // 에러. Box<Toy>에는 Apple 담을 수 없음
System.out.println(fruitBox);
System.out.println(appleBox);
System.out.println(toyBox);
}
}
class Box<T>{
ArrayList<T> list = new ArrayList<>();
void add(T item) {list.add(item);}
T get(int i) { return list.get(i);}
int size() { return list.size();}
public String toString() { return list.toString();}
}
- 지네릭 클래스의 객체를 생성할 때는, 참조변수와 생성자에 대입된 타입이 일치해야합니다. 그러나 지네릭 클래스 타입이 상속관계에 있고, 대입된 타입이 같은 것은 괜찮습니다.
- JDK 1.7부터는 추정이 가능한 경우 타입을 생략할 수 있습니다.
제한된 지네릭 클래스 사용하기
class FruitBox<T extends Fruit>{ // Fruit의 자손만 타입으로 지정 가능합니다.
ArrayList<T> list = new ArrayList<T>();
}
- 지네릭 타입에 'extends'를 사용하면, 특정 타입의 자손들만 대입할 수 있게 제한할 수 있습니다.
- <? extends T> 와일드 카드의 상한 제한으로, T와 그 자손들만 사용 가능합니다.
- <? super T> 와일드 카드의 하한 제한으로, T와 그 조상들만 사용 가능합니다.
- <?> 제한 없고, 모든 타입이 가능합니다.
지네릭 메서드
메서드의 선언부에 지네릭 타입이 선언된 메서드를 지네릭 메서드라 합니다.
static <T> void sort(List<T> list, Comparator<? super T> c)
static 멤버에는 타입 매개변수를 사용할 수 없지만,이처럼 메서드에 지네릭 타입을 선언하고 사용하는 것은 가능합니다.
열거형
열거형은 서로 관련된 상수를 편리하게 선언하기 위한 것으로, 여러 상수를 정의할 때 사용하면 유용합니다.
자바의 열거형은 '타입에 안전한 열거형'으로 실제 값이 같아도 타입이 다르면 컴파일 에러가 발생합니다. 이처럼 값뿐만아니라 타입까지 체크하기 때문에 타입에 안전하다고 말합니다.
enum 열거형이름 { 상수명1, 상수명2...}
메서드 | 설명 |
Class getDeclaringClass() | 열거형의 class객체를 반환합니다. |
String name() | 열거형 상수의 이름을 문자로 반환합니다. |
int ordinal() | 열거형 상수가 정의된 순서를 반환합니다. |
T valueOf(Class<T> enumType, String name) | 지정된 열거형에서 name과 일치하는 열거형 상수를 반환합니다. |
package ch11;
enum Direction {EAST, SOUTH, WEST, NORTH};
public class EnumEx1 {
public static void main(String[] args) {
Direction d1 = Direction.EAST;
Direction d2 = Direction.valueOf("WEST");
Direction d3 = Direction.valueOf(Direction.class,"EAST");
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));
System.out.println("d1.compareTo(d3) ? " + (d1.compareTo(d3)));
System.out.println("d1.compareTo(d2) ? " + (d1.compareTo(d2)));
switch (d1) {
case EAST :
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){
System.out.printf("%s=%d%n",d.name(),d.ordinal());
}
}
}
애노테이션
프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이 바로 애노테이션입니다.
애너테이션 | 설명 |
@Override | 컴파일러에게 오버라이딩하는 메서드라는 것을 알립니다. |
@Deprecated | 앞으로 사용하지 않을 대상에 붙입니다. |
@SuppressWarnings | 컴파일러의 특정 경고 메시지가 나타나지 않게 해줍니다. |
@SafeVarargs | 지네릭스 타입의 가변인자에 사용합니다. |
@FunctionalInterface | 함수형 인터페이스라는 것을 알립니다. |
@Native | native메서드에 참조되는 상수 앞에 붙입니다. |
@Target | 애너테이션이 적용 가능한 대상을 지정하는데 사용합니다. |
@Documented | 애너테이션의 정보가 javadoc로 작성된 문서에 포합되게 합니다. |
@Inherited | 애너티이션이 자손 클래스에 상속되도록 합니다. |
@Retention | 애너테이션이 유지되는 범위를 지정하는데 사용합니다. |
@Repeatable | 애너테이션을 반복해서 적용할 수 있게 합니다. |
- @Override를 사용하면 컴파일러가 같은 이름의 메서드가 조상에 있는지 확인하고 없으면 에러메시지를 출력해줍니다.
- @Deprecated는 더이상 사용되지 않는 필드나 메서드에 @Deprecated가 붙어있습니다.
애너테이션 타입 정의
새로운 에너테이션을 정의하는 법은 다음과 같습니다.
@interface 애너테이션이름{
타입 요소이름();
}
-애너테이션 내 선언된 메서드를 '애너테이션의 요소'라고 합니다.
- 요소의 타입은 기본형, String, enum, 애너테이션, class만 허용됩니다.
- 예외를 선언할 수 없습니다.
- 요소를 타입 매개변수로 정의할 수 없습니다.
'Language > Java' 카테고리의 다른 글
입출력 I/O (0) | 2022.01.31 |
---|---|
Thread (0) | 2022.01.16 |
Collection Framework (0) | 2022.01.02 |
날짜와 시간 & 형식화 date, time and formatting (0) | 2021.12.25 |
java.lang패키지와 유용한 클래스 (0) | 2021.12.19 |