Java Ch 12 지네릭스

Java Ch 12 지네릭스

● ch 12-1 지네릭스란?

· 지네릭스

컴파일 시 타입을 체크해 주는 기능(원래 있지만, 그 한계를 넘도록 해준 것) JDK 1.5

객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여줌

ex) import java.util.ArrayList; ArrayList tvList = new ArrayList ; //Tv객체만 저장할 수 있는 ArrayList 생성 tvList.add(new Tv()); tvList.add(new Audio()); // 컴파일 에러 // 배열에 숫자와 String 숫자를 add하면 컴파일 에러가 없다. 그리고 같아보인다. [10, 20, 30] // “30”이여도 // 그리고 Integer I = (Integer) list.get(2)을 해도 컴파일 에러 없다. list.get(2)가 반환하는게 Object 타입이니까 // 하지만 실행하면 java.lang.ClassCastException 이라는 에러가 나온다. 이는 형변환으로 인한 에러(실행 시 에러) ==> 이게 컴파일러의 한계이다. list.get(2)를 실행할 때 object를 반환하기에 통과한 거지만 실제로 뭐가 들어있는지까지 알 수 없다... 그래서 실행할 때는 에러가 발생하는 것.

===> 가능하면 실행시 발생 에러보다 컴파일 에러가 훨씬 낫다. 어떻게하면 컴파일 때 에러를 잡을 수 있을까 고안한 것이 지네릭스이다.

## 오토박싱 list.add(10) <= list.add(new Integer(10));

// 지네릭스를 사용하게 되면 이후, 형변환 생략가능

ex) Integer I = list.get(2); // 어차피 Integer 타입인 거 아니까 // 가능은 하다. 매번 형변환 타입을 적어주어야하지만 모든 타입을 다 받을 수 있다.

## 중요: 지네릭스를 배웠으니 이제부터 Collection을 만들 때, ArrayList list = new ArrayList ;를 꼭 써줘야한다! // ArrayList는 일반 클래스이지만, <타입>을 적어주면 지네릭 클래스로 바뀐다.

## 의문: 왜 list.get()을 하면 Object가 반환되나? get 메서드가 그렇게 정의되어있나? return Object()로? \

==> Object배열은 모든 종류의 객체를 저장해야하는데. 특정 객체 타입을 반환할 수 없다. 들어오는 것도 Object타입이니 나가는 것도 Object타입이다. 그리고 메서드도 그렇게 정의되어있다.

지네릭스의 장점

타입 안정성을 제공한다.

2. 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해진다.

지네릭스의 역할

실행 중 발생 에러를 Compile 에러로 수정하는 것이다. 개발단계에서 해결할 수 있도록. 런타임에러는 시스템 종료됨.

// 비슷한 사례: NullPointerException 에러의 경우 String str= null; 선언하고 str.length();로 메서드호출하면 발생. 그러니 String str = “”; 빈문자열로 선언하고, str.length();를 호출하면 0으로 나온다.

+ Object [] objArr = null; 보다 Object [] objArr = new Object [0] // 길이가 0인 배열로 선언하는 것이다.

● Ch 12-2 타입변수

지네릭 클래스를 작성할 때, Object 타입(일반 클래스) 대신 타입 변수(E)(지네릭 클래스)를 선언해서 사용

// 일반클래스에서 지네릭클래스로 바뀌는 것(Object를 포함한 클래스들이 이제는 타입변수 클래스로)

// E 대신 T, EE 로 쓰기도 한다.

- 객체를 생성시, 타입 변수(E)대신 실제 타입(Tv)을 지정(대입)

// 위에 있는 E 대신에 실제 타입 Tv를 대입. 이로 인해 tvList.get(0)이 원래 일반 클래스에서는 Object 타입으로 반환됬으나, public Tv get(int index); 지네릭클래스로 바뀌었으니 Tv타입으로 반환되는 것이다.

## Ctrl + O 하면 보유하고 있는 클래스 목록으로 간다. ArrayList list = new ArrayList ();에서 ArrayList에 Ctrl + O 하면 E타입변수 지네릭클래스 목록으로 간다.

● Ch 12-4,5 지네릭스 용어, 지네릭 타입과 다형성

· 지네릭스 용어

- Box: 지네릭 클래스, 'T의 BOX' 또는 'T BOX'라고 읽는다

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

- Box : 원시 타입(raw type)

ch 12-4 지네릭스 용어

· 지네릭 타입과 다형성

// 매개변수의 다형성!!

● Iterator 와 HashMap

· Iterator

- 클래스를 작성할 때, Object타입 대신 T와 같은 타입 변수를 사용

//일반 클래스->지네릭 클래스처럼 Iterator 에서도 지네릭을 통해 형변환이 필요 없어짐.

// 의문: Iterator it = list.iterator();에서 list 앞에 왜 형변환을 하지않는지 생각해볼것!

· HashMap

- 여러 개의 타입 변수가 필요한 경우, 콤마(,)를 구분자로 선언

- HashMap map = new HashMap(); // 생성

- map.put("자바왕", new Student("자바왕",1,1,100,100,100)); // 데이터 저장

===> Key와 Value로 저장하는 경우, 타입변수 K, V 활용

// 왜 key 앞에 K로 안 바꾸고 Object로 남겨놓느냐? => get 메서드 안에 hash라는 메서드에 Object Key를 넣기에 불필요하게 형변환할 필요가 없어서..

· 예제 Ex 12_2

JDK 1.7부터 생성자에 타입지정 생략 가능해졌다!

● Ch 12-9~11 제한된 지네릭 클래스, 지네릭스의 제약

· 제한된 지네릭 클래스

- extends로 대입할 수 있는 타입을 제한

- 인터페이스인 경우에도 implements 가 아니라 extends 를 쓴다

// 클래스 타입과 인터페이스를 같이 쓸 떄는 콤마 가 안되고 무조건 & 로 써야한다.

ex) class FruitBox extends Box {}

==> Eatable은 interface, Fruit는 Eatable을 구현한다고 주어진 상황. 위 class의 뜻은 들어올 수 있는 T 타입은 Fruit의 자손이면서 Eatable을 구현한 것이라고 생각하면 된다. 그리고 뒤에 extends Box는 class Box{}에서 기능과 메서드 들을 선언할 건데, 그걸 상속받는다는 뜻이다. 그리고 기능과 메서드들의 타입에 지정한 타입으로 대입.

## 주의: 상속받은 것은 extends, interface를 구현한 것은 implements!!

## 예제 12-3 꼭 해보기!!

· ch 12-11 지네릭스의 제약

- 타입 변수에 대입은 인스턴스 별로 다르게 가능.

ex) Box appleBox = new Box(); // Apple 객체만 저장가능

Box grapeBox = new Box(); // Grape 객체만 저장 가능

- static 멤버에 타입 변수 사용 불가

// static 은 모든 인스턴스의 공통이기에 인스턴스마다 다르게 지정할수있는것을 static 멤버에 적용할 수 없다.

- 배열 생성할 때 타입 변수 사용불가. 타입변수로 배열 선언은 가능.

# 객체 생성하거나 배열 생성 할 때 new 다음에 T가 오면 안된다.

Why? new 연산자는 뒤에 타입이 확정되어있어야 하는데, T는 어떤 타입이 올지 모르니까.

## 헷갈림 주의: 선언 vs 생성

String[] name; // 배열을 선언 name = new String[3]; // 배열을 생성 String[] name = new String[3]; // 배열의 선언과 생성을 동시에

● ch 12-12~14 와일드카드 지네릭 메서드

· ch 12-12 와일드 카드

- 하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능

// 원래 지네릭스 타입에는 항상 선언 쪽과 생성쪽 타입이 일치해야한다 // 부모, 자손 관계여도 양쪽 다 일치해야..

// 일치하지않으면 오류가 나는데 이 답답함을 해결하기 위해서 와일드카드를 쓴다. 양쪽 일치하지않아도 ok

· 와일드 카드는 3가지가 있는데

1. 와일드 카드의 상한 제한. T와 그 자손들만 가능 // 이걸 제일 많이 쓴다.

2. 와일드 카드의 하한 제한. T와 그 조상들만 가능.

3. 제한없음. 모든타입이 가능 와 동일

=> 와일드 카드를 씀으로써 서로 다른 지네릭스 타입을 참조할수 있는것이다. // 다형성처럼

- 메서드의 매개변수에도 와일드 카드를 사용할수 있다.

ex) --- AAA(FruitBox box) { sop(new FruitBox()); sop(new FruitBox()); // 와일드카드를 쓰지않고 만 지정한 경우, 첫 번째 sop 메서드밖에 못쓰지만 와일드카드를 쓰면 둘 다 가능

· 지네릭메서드

- 지네릭 타입이 선언된 메서드 ( 타입 변수는 메서드 내에서만 유효 ) // 앞에서 배운 건 지네릭 클래스

- 클래스의 타입 매개변수 와 메서드의 타입 매개변수 는 별개. // 지네릭클래스보다 지네릭 메서드에 있는 가 우선된다. 이는 iv vs lv에서 lv가 우선되는 것과 같다.

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

- 메서드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가(하지만 이런 경우 잘 없다)

· 지네릭 메서드 vs 와일드카드 메서드

ex) static Juice makeJuice(FruitBox box) vs static Juice makeJuice(FruitBox box)

- 기본적으로 와일드카드의 목적은 하나의 참조변수로 대입된 타입이 다른 여러 지네릭 객체를 다루기 위한 것.

지네릭 메서드는 지네릭클래스처럼 메서드를 호출할때마다 다른 타입을 대입할수있다. 용도가 조금 다르다. 와일드카드가 쓸수없을때 지네릭메서드를 쓴다.

● Ch 12-15~16 지네릭 타입의 형변환

· 지네릭 타입의 형변환

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

// 원시타입과 지네릭 타입을 섞어쓰면 안되고 반드시 지네릭타입을 써줘야한다. 오류는 안 나지만 실행시 런타임에러

// why? Box 타입에 add 메서드가 있는데, Box objBox = null; Box box = (Box)objBox;를 해버리면 box.add()를 할 때, 타입만 들어가는게 아니라 모든 타입 다 받는 원래 일반클래스의 add메서드이기에.

- 와일드카드가 사용된 지네릭 타입으로는 형변환 가능

// 서로 다른 타입이 대입된 지네릭 타입간에는 형변환이 안된다.

ex) Box -> Box 에러 Box objBox = (Box) new Box(); //에러. 형변환 불가능.

하지만 와일드카드가 사용된 지네릭 타입으로는 형변환 가능. 와일드카드가 적용된 Object 와 그 자손들끼리는 생략 가능.

// 형변환할 때, 타입이 불일치하면 (Box를 써줘야하는데, 생략 가능한 것이다. (그냥 쓰자)

// 와일드카드->타입변수와 타입변수->와일드카드 모두 형변환 가능. but 전자는 타입이 명확하지않은 객체를 명확한 타입으로 형변환하려고하니까 경고 발생한다. 이 때는 타입 생략 불가라 꼭 써줄 것

· ch 12-16 지네릭 타입의 제거

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

// object를 로 타입변수를 적어주는데, 컴파일하면 이 가 object로 바꿔준다. 지네릭스가 없는 하위버전과 호환성을 갖기위해서!! => 지네릭타입은 컴파일떄까지만 존재하는것이다.

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

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

// 왼쪽 코드는 반환타입이 Object 이므로 return (T)list.get(i) 가 정석이나 형변환이 생략된 것임.

우리가 형변환을 생략한다고해서 생략해도 되는게 아니다. 컴파일러가 자동으로 해주는 것

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

● Ch 12-17~20 열거형(enum) 열거형의 조상

· 열거형(enum)

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

// 상수가 있는데 일일이 하나씩 값을 지정해주면 너무 오래 걸린다.

if(Card.CLOVER==Card.TWO) // 결과는 둘 다 0이므로 true 지만 카드종류와 카드 수 서로 의미하는바가 달라서 false 가나와야 의미상 맞다. 그래서 오른쪽과 같이 간단히 할 수 있다. 무늬는 무늬끼리 숫자는 숫자끼리 간단하게 정의할 수 있게 해놓는 것이 열거형이다. if(Card.kind.CLOVER==Card.Value.TWO ) {

=> 이 문장은 컴파일 에러가 나온다. 타입이 달라서 비교불가능하다는 것이다.

//자바 열거형은 값과 타입 둘 다 체크한다.

· ch 12-18 열거형의 정의와 사용

- 열거형을 정의하는 방법 //기본적으로 인덱스를 0,1,2,3,,로 준다.

enum 열거형이름 {상수명1, 상수명2,,,,}

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

class Unit { int x,y; Direction dir; // 열거형 인스턴스 변수를 선언 // 위에서 선언한 상수 중 하나의 값만 들어올수있다. void init() { dir = Direction.EAST; // 유닛의 방향을 EAST 로 초기화 } }

-열거형 상수를 비교할때는 == 하고 compareTo() 를 사용가능하다.

if(dir==Direction.EAST) { // dir값이 EAST인지 확인하고 있다. 아까 초기화해줫으니 참이 뜬다. x++; } else if (dir > Direction.WEST) { // 에러발생. 열거형 상수에 비교연산자 사용불가 } else if (dir.compareTo(Direction.WEST) > 0 { // compareTo()는 가능 // 열거형 상수에 비교연산자 사용불가 // CompareTo() 같으면 0 왼쪽이 크면 양수, 오른쪽 음수(뺄셈이다)

· ch 12-19 열거형의 조상 - java.lang.Enum // Enum 이라는 클래스가 있다. (모든열거형의 조상)

- 모든 열거형은 Enum 의 자손이며, 아래의 메서드를 상속받는다.

// getDeclaringClass 는 잘 안 씀. 클래스 객체는 설계도. 해당 메서드가 선언된 클래스 정보를 리턴한다.

=> 일반적으로 Enum을 리턴하겠지. 오버라이딩했다면 자손 클래스일거고

// ordinal은 순서만... 값과는 관련x

++ values() 와 valueOf()는 컴파일러가 이 메서드들을 자동으로 추가한다. 우리는 열거형 상수에서 6개의 메서드들을 자동으로 사용할 수 있는 것이다.

ex) static E[] values() static E valueOf(String name) // values 사용법 Direction [] dArr = Direction.values(); // 열거형 상수가 가지고있는 모든 상수들을 배열로 반환한다. // valueOf 사용법 Direction d= Direction.valueOf("WEST"); 는 열거형 상수 이름을 반환한다 Direction.WEST 하고 똒같음

// 셋중의 하나를 골라서 쓰면된다. 주로 첫번쨰를 많이씀

## 중요: enum Direction 안에 있는 열거형 상수들은 기본값이 아니라 객체이다. 그래서 equals와 compareTo를 쓴다. ==는 가능하나, 비교연산자는 불가.

● ch 12-21, 22 열거형에 멤버 추가하기

· ch 12-21 열거형에 멤버 추가

- 불연속적인 열거형 상수의 경우, 원하는 값을 괄호()안에 적는다. // 여기있는 괄호는 생성자() 호출이다.

==> 생성자 호출은 만들 그릇을 불러온다고 생각하면 된다. 생성자 추가는 그릇을 만들어주는 것이고.

ex) enum Direction { EAST(1),SOUTH(5),WEST(-1),NORTH(10) }

// 여러개의 값을 넣을수도있다. EAST(1,">") //// 1과 문자열 >

- 이렇게 괄호()를 사용할려면 단순히 괄호, 숫자만 넣으면 안되고 iv와 생성자를 새로 추가해줘야 한다.

==> EAST,SOUTH,WEST,NORTH 값들을 저장할 iv 를 생성해주어야 한다.

- 열거형의 생성자는 항상 private 이므로 생략된 것이다. enum 클래스 전체가 private. 외부에서 객체생성 불가

Direction d= new Direction(1); // 에러, 열거형의 생성자는 외부에서 호출불가 ## 잘 이해가 ㅠㅠ

===> 이게 enum 클래스를 거치지않으면 안된다는 소리인가 ????

· 예제 Ex 12_6

- Direction 안에 모두 값을 2개씩 가진다.

첫번째 값을 int 상수로 두었고 두번째 값을 String symbol 을 선언했다. 그리고 생성자도 추가해줬다.

of 라는 메서드를 이용해서 상수들중의 하나를 얻어올수있게 했다. 매개변수를 주면 거기에 맞는 상수들중 하나가 반환이 된다.

- Direction2.EAST.rotate(); 의 경우, values를 이용해서 1이면 1번 90도로 시계방향 회전하게끔 만들었다. 시계방향 회전은 배열에서 순서대로 가는 것으로 정의해줬다. 그리고 rotate 메서드에 대해 음수인 경우, 4이상인 경우 등을 고려했다.

● ch 12-23~24 애너테이션이란? ## 애너테이션을 만들 일이 잘 없으니, 일단은 이런게 있다만 알아두고 나중에 만들 때 공부하면 된다.

· 애너테이션이란 ?

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

// 이전에는 소스 파일과 설정(XML 파일)을 따로따로 보관했는데 서로 불일치가 생겨서 소스파일에 설정 정보를 추가하였다.(정보 제공) 그게 바로 애너테이션이다. 기존문법을 바꾸지 않아도 된다. 애너테이션으로 하면 각자 자기코드에 필요한 설정을 추가하면된다.

// javadoc 안의 @-- 은 javadoc.exe을 위해서만 유용한 정보를 제공하는 것이다.

// @로 시작, 첫글자 대문자로

// 메서드 위에 @Test만 적어주면 이 메서드가 테스트 대상임을 테스트 프로그램에게 알린다.

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

// 아래 누런 부분 애너테이션은 메타 애너테이션이라 하며, 애너테이션을 만들 때 사용

● Ch 12-25~28 표준 애너테이션

· @Override

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

// 오버라이딩할 때 메서드 이름을 잘못적는 실수를 많이 한다.

// @Override를 적어주면, 이름을 잘못적을 때 컴파일러가 에러가 알려준다.

· @Deprecated

- 앞으로 사용하지 말라고 권장하는 필드나 메서드에 붙인다. 그리고 해당 메서드에 줄이 그어진다.

// 사용 권장 안함. 사용 안 하거나 더 좋은게 나와서 쓰지말라고 하는 것. but 하위호환성 때문에 그냥 둔거다.

- @Deprecated 가 붙은 대상이 사용된 코드를 컴파일하면 나타나는 메시지

// 컴파일할때 -Xlint:deprecation 을 같이 쓰고 해라 그럼 자세하게 알려준다는 의미이다. 에러는 아니다.

=> 이걸하면 메시지 대신에 상세 정보로 나온다.

// 에러가 안 나오고, 컴파일이 알아서 해주기에 cmd 창에서 확인해야한다.

// Alt+enter 치면 해당 소스 코드 파일의 속성이 나온다. 여기서 단추를 누르면 탐색기에서 소스코드 경로 복사!!

· @FunctionalInterface (컴파일러가 사용하는 애너테이션)

- 함수형 인터페이스에 붙이면 컴파일러가 올바르게 작성했는지 체크(@Override처럼 있으면 실수 방지에 좋은 것)

- 함수형 인터페이스에는 하나의 추상메서드만 가져야한다는 제약이 있음// 0개나 2개 이상이면 컴파일러가 잘못작성했다고 알려줌

· @SuppressWarnings (컴파일러가 사용하는 애너테이션)

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

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

// ArrayList 는 지네릭스 클래스인데 <타입> 을 쓰지않으면 unchecked 라는 경고가 발생하는데 그걸 발생하지않게 하기위함이다. 이 경고를 내가 알고있으면 괜찮아, 내가 알아서 고칠게 라는 효과!!

- 두개 이상의 경고를 동시에 억제하려면 다음과 같이 한다. 배열처럼 쓰면 된다.

// 이렇게 deprecation 경고가 떴는데, @SuppressWaarnings("deprecation")을 적어주면 해당 경고메시지 안 나옴

## 중요: 경고라는것은 잠재적위험이다. 경고를 억제하지않으면 같은 경고가 계속 발생한다. 특히, 새로 발생하는 경고를 놓칠 수 있으니 확인한 경고는 억제를 해주고 새로운 경고를 알 수 있도록 하는 것이 좋다.

● ch 12-29~33 메타 애너테이션

· 메타 애너테이션

- 애너테이션을 위한 애너테이션이다. 애너테이션을 만들때 사용

- 메타 애너테이션은 java.lang.annotaion 패키지에 포함

· @Target

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

// 아래는 SuppressWarnings 애너테이션의 실제소스인데 이 애너테이션을 어디에 붙일수있는지 알려주는 것이다.

Type는 클래스나 ,인터페이스, FIELD 는 iv. 아래 쪽을 참고해서 @Target 옆 괄호 안에 넣으면 된다.

- 예를들면 MyAnnotation을 애너테이션 만들 때 인터페이스 앞에 @(골뱅이) 를 붙인다.

이 애너테이션을 붙일 수 있는곳은 필드(클래스나,인터페이스),타입(멤버변수),타입유스(참조변수) 라고 정의하고, 적용대상이 --인 경우 --를 구현한다라고 정의한다.

· @Retention

- 애너테이션이 유지(retention) 되는 기간을 지정하는데 사용

// SOURCE와 RUNTIME만 알면 된다.

- 컴파일러를 위한 애너테이션은 실행 시에는 필요없다 컴파일러가 실행하고 끝나기에 유지정책이 SOURCE 이다.

클래스파일에 남아있을 이유는 없다.

// 실행 시에 사용가능한 애너테이션의 정책은 RUNTIME으로!

· @Documented, @Inherited ==> 잘 안 쓴다. 이런 것들이 있다정도만

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

- 애너테이션을 자손 클래스에 상속하고자 할 때, @Inherited를 붙인다.

· @Repeatable ==> 잘 안 쓴다.

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

- @Repeatable 이 붙은 애너테이션은 반복해서 붙일 수 있다. 애너테이션이 Repeatable 이어야 가능

● ch 12-34~37 애너테이션 타입 정의하기, 애너테이션의 요소

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

- 애너테이션을 직접 만들어 쓸 수 있다. @를 안 붙이면 그냥 인터페이스다.​

@interface 애너테이션이름 { 타입 요소이름(); // 애너테이션의 요소를 선언한다. // 추상 메서드다. ---- }

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

애너테이션이 또 다른 애너테이션의 요소로 들어갈수도 있다.

// 그리고 요소 값들을 다 적어줘야한다. // 이름하고 값을 같이 적어줬기 때문에 순서가 필요없음.

// 만들어서 호출하는 일은 사실 거의없다. 주로 우리가 오른쪽처럼 사용하는 경우가 많다.

// 이 애너테이션에서 정보를 얻는 프로그램이 있다고 할 때, 참조변수.count를 호출하면 3이 반환되는 것이다!

· 애너테이션의 요소

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

// 원래 사용하는 쪽에서 @TestInfo 에 값을 지정해줘야하는데, 이미 default값이 있어서 적지않으면 count=1로 간주

- 요소가 하나이고 이름이 value 일때는 요소의 이름 생략가능

ex) 원래는 @TestInfo(value="passed" 라고 써야하는데 @TestInfo("passed")로 생략가능

- 요소의 타입이 배열인 경우, 괄호{}를 사용해야 한다. 하나라면 {}생략 가능

· ch 12-36 모든 애너테이션의 조상 - java.lang.annotation.Annotation

- Annotation 은 모든 애너테이션의 조상이지만 상속은 불가능하다. 그냥 모든 애너테이션이 자연스럽게 물려받는다.

// Annotation은 위와 같은 메서드들을 가지고있다 (추상메서드) 이 추상메서드들을 구현하진 않지만 사용할 수는 있다. 그래서 모든 애너테이션도 이와 같이 추상메서드를 구현하지않아도 사용은 가능. 어차피 사용할 때 구현할테니

· 마커 애너테이션 -Marker Annotation

- 요소가 하나도 정의되지 않은 애너테이션. 그냥 이런 게 있다. 사용할 때도 값 지정하지 않는다.

· 애너테이션 요소의 규칙

- 애너테이션의 요소를 선언할 때 아래의 규칙을 반드시 지켜야한다

1. 요소의 타입은 기본형, String, enum, 애너테이션, Class(설계도객체)만 허용됨

2. 추상메서드 괄호()안에 매개변수를 선언할수없다.

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

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

## 유효하지않은 애너테이션은 무시된다.

## 참조변수.getAnnotations // 참조변수의 클래스에 붙은 모든 Annotation을 갖고온다.(유효x는 불러오지x)

## 서블릿, 스프링 프레임워크를 쓰면 애너테이션을 많이 쓰게 될 것이다.

from http://ing-til-death.tistory.com/67 by ccl(A) rewrite - 2021-10-08 22:01:23