Yapp a.a study 2 reflection+annotation

Post on 31-May-2015

501 views 12 download

description

Java Reflection, Annotation 이해 및 활용

Transcript of Yapp a.a study 2 reflection+annotation

Reflection+ Annotation

2013. 7. 23이준영

13년 7월 23일 화요일

Class?

• 클래스를 구성하는 것들

• Fields,

• Methods,

• Constructors

13년 7월 23일 화요일

Class detailsField

Constructor

Method

13년 7월 23일 화요일

이클립스는어떻게

Contents Assist(Ctrl + Space)를지원할까?

13년 7월 23일 화요일

이클립스는클래스가 어떻게 생겨먹었는지 알고 있다.

13년 7월 23일 화요일

Class 클래스• 어떤 클래스의 모양(구성)을 알고 있는 클래스

• Fields,

• Methods,

• Constructors

• 상속 받은 것,정의한 것,인터페이스 등

13년 7월 23일 화요일

예제 자바 프로젝트 생성

13년 7월 23일 화요일

Class 클래스로 클래스 살펴보기

• 파헤쳐볼 WishItem 클래스 작성

13년 7월 23일 화요일

Class 클래스로 클래스 살펴보기

• 파헤쳐볼 WishItem 클래스 작성

13년 7월 23일 화요일

Class 클래스로 클래스 살펴보기

• 파헤쳐볼 WishItem 클래스 작성

public class WishItem implements Serializable{ private int id; private String name; private String createdTime; public WishItem(String name, String createdTime) { this(-1, name, createdTime); } public WishItem(int id, String name, String createdTime) { this.id = id; this.name = name; this.createdTime = createdTime; } public int getId() { return id; }

public void setId(int id) { this.id = id; }

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public String getCreatedTime() { return createdTime; }

public void setCreatedTime(String createdTime) { this.createdTime = createdTime; }}

13년 7월 23일 화요일

Class 클래스로 클래스 살펴보기

• 파헤쳐볼 WishItem 클래스 작성

public class WishItem implements Serializable{ private int id; private String name; private String createdTime; public WishItem(String name, String createdTime) { this(-1, name, createdTime); } public WishItem(int id, String name, String createdTime) { this.id = id; this.name = name; this.createdTime = createdTime; } public int getId() { return id; }

public void setId(int id) { this.id = id; }

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public String getCreatedTime() { return createdTime; }

public void setCreatedTime(String createdTime) { this.createdTime = createdTime; }}

13년 7월 23일 화요일

우린 왜 IDE를 쓸까?잠깐, 다른 이야기

13년 7월 23일 화요일

우린 왜 IDE를 쓸까?좀 더 편하고 빠르게 개발하기 위해서

잠깐, 다른 이야기

13년 7월 23일 화요일

Eclipse의 소스 생성 기능

13년 7월 23일 화요일

WishItem 클래스 정보 읽어보기

• Main 메서드 작성main 쓰고 Ctrl + Space bar

• 클래스의 Class 클래스 인스턴스를 가져오기Class<WishItem> clazz = WishItem.class

Class<? extends WishItem> clazz = obj.getClass()

13년 7월 23일 화요일

.class vs .getClass()

• .class는 타입 그대로의 클래스를 가져옴

• .getClass()는 인스턴스의 실제 타입의 클래스를 가져옴

Animal

Dog

상속

Animal a = new Animal();Animal d = new Dog();

d 의 클래스 정보를 얻기 위해서는Animal.class가 맞을까, d.getClass()가 맞을까?

13년 7월 23일 화요일

clazz.

• getDeclaredField(String name) - Field

• getDeclaredFields() - Fields[]

• getDeclaredMethod(String name) - Method

• getDeclaredMethods() - Method[]

• getDeclaredConstructor(Class<?>...paramTypes)

• getDeclaredConstructors() - Constructor

13년 7월 23일 화요일

clazz. ...

13년 7월 23일 화요일

clazz. ...

13년 7월 23일 화요일

clazz. ...

공부 많이 해야겠죠?그렇다고 외우진 마세요.

그런게 있었다는 것만 기억!

13년 7월 23일 화요일

하나씩 해 봅시다.

• Field 가져오기 WishItem wi = new WishItem(0, "2013.7.23", "세상의 모든 지식"); Class<? extends WishItem> clazz = wi.getClass(); try { Field idField = clazz.getDeclaredField("id"); // 필드의 이름 출력 System.out.println(idField.getName()); } catch (NoSuchFieldException e) { // 찾는 이름의 필드가 없을 때 e.printStackTrace(); } catch (SecurityException e) { // 접근 제한 발생할 때 e.printStackTrace(); }

13년 7월 23일 화요일

• Field의 값 보기, 바꾸기 try { Field idField = clazz.getDeclaredField("id"); // 필드의 이름 출력 System.out.println(idField.getName()); // 접근이 가능하도록 설정 idField.setAccessible(true); // 필드 값 가져오기 System.out.println(idField.get(wi)); // idField의 값을 15로 변경 idField.set(wi, 15); // WishItem 객체에 실제로 바뀌었는지 확인 System.out.println(wi.id); // 다시 접근이 불가능하도록 설정 idField.setAccessible(false);

...

13년 7월 23일 화요일

• Field의 값 보기, 바꾸기 try { Field idField = clazz.getDeclaredField("id"); // 필드의 이름 출력 System.out.println(idField.getName()); // 접근이 가능하도록 설정 idField.setAccessible(true); // 필드 값 가져오기 System.out.println(idField.get(wi)); // idField의 값을 15로 변경 idField.set(wi, 15); // WishItem 객체에 실제로 바뀌었는지 확인 System.out.println(wi.id); // 다시 접근이 불가능하도록 설정 idField.setAccessible(false);

...

13년 7월 23일 화요일

• Field의 값 보기, 바꾸기 try { Field idField = clazz.getDeclaredField("id"); // 필드의 이름 출력 System.out.println(idField.getName()); // 접근이 가능하도록 설정 idField.setAccessible(true); // 필드 값 가져오기 System.out.println(idField.get(wi)); // idField의 값을 15로 변경 idField.set(wi, 15); // WishItem 객체에 실제로 바뀌었는지 확인 System.out.println(wi.id); // 다시 접근이 불가능하도록 설정 idField.setAccessible(false);

...

13년 7월 23일 화요일

• 모든 Field 가져오기

Field[] fields = clazz.getDeclaredFields(); for(Field field : fields) { System.out.println(field.getName()); }

Field의 배열 형태로 반환

13년 7월 23일 화요일

• 특정 Method 가져오기getName 메서드 살짝 수정 public String getName() { System.out.println("위시 아이템 이름은 " + name); return name; }

try { // 특정 Method 가져오기 Method getNameMethod = clazz.getDeclaredMethod("getName"); // 메서드의 이름 확인 System.out.println(getNameMethod.getName()); } catch (NoSuchMethodException e) { // 그런 메서드가 없음! e.printStackTrace(); } catch (SecurityException e) { // 시큐리티! 시큐리티! e.printStackTrace(); }}

13년 7월 23일 화요일

• 메서드 실행하기

• 실행 결과

// 메서드 실행하기 String name = (String)getNameMethod.invoke(wi); // 가져온 값 확인 System.out.println("가져온 값 : " + name);

위시 아이템 이름은 세상의 모든 지식가져온 값 : 세상의 모든 지식

13년 7월 23일 화요일

Q : 모든 메서드를 가져와서 이름 출력해 보기

13년 7월 23일 화요일

• Class 클래스를 이용해 인스턴스 만들기

try { WishItem item = clazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }

13년 7월 23일 화요일

• Class 클래스를 이용해 인스턴스 만들기

try { WishItem item = clazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }

newInstance 메서드는 해당 클래스가 매개변수가 없는기본 생성자를 가지고 있어야 사용 가능

13년 7월 23일 화요일

기본 생성자를 만들거나

혹은

Constructor를 이용

13년 7월 23일 화요일

• Constructor를 이용해서 인스턴스 만들기try { // 생성자 가져오기 Constructor cons = clazz.getDeclaredConstructor(int.class, String.class, String.class); // 생성자를 통해서 인스턴스 생성 WishItem item = (WishItem) cons.newInstance(4, "2013. 7. 23", "갤럭시 S4"); // 실제로 잘 생성되었는지 값 확인 System.out.println(item.getName());} catch (Exception e) { } // 예외는 길이 상 생략..

13년 7월 23일 화요일

Reflection?

• 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법

• 타입은 알고 있지만 형변환을 할 수 없는 상태에서 메서드를 호출

13년 7월 23일 화요일

Reflection?

• 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법

• 타입은 알고 있지만 형변환을 할 수 없는 상태에서 메서드를 호출

앞에서 살펴본 Class 클래스 가지고 놀기

13년 7월 23일 화요일

Annotation

• 사전적 정의 : 주석

• Meta Data : 데이터에 대한 데이터

• 어노테이션은 @으로 표현

13년 7월 23일 화요일

Annotation

• 사전적 정의 : 주석

• Meta Data : 데이터에 대한 데이터

• 어노테이션은 @으로 표현@Override@Deprecated@SuppressWarnings

최소한 @Override는 본적 있죠?

13년 7월 23일 화요일

일단 만들어 봅시다.

• File >> New

13년 7월 23일 화요일

• 그럼 이런 파일이 생성

• WishItem 클래스의 name 필드에 붙여보기

public @interface FirstAnno {

}

@FirstAnnoprivate String name;

짠!

13년 7월 23일 화요일

• Annotation에 값 담기

• WishItem으로 돌아가보면..

• 그릇이 생겼으니 담아줘야.

public @interface FirstAnno { public int value();}

@FirstAnnoprivate String name;

@FirstAnno(27)private String name;

13년 7월 23일 화요일

• 또 다른 값 담아보기

• 다시 WishItem 클래스로..

public @interface FirstAnno { public int value(); public String weekday();}

@FirstAnno(value=27, weekday="화요일")private String name;

13년 7월 23일 화요일

처음에는 value 라고 적어주지 않았었는데..?@FirstAnno(27)private String name;

13년 7월 23일 화요일

value는 어노테이션의 기본값을 담는 이름>> 이름 없이도 값을 담는 어노테이션 변수

13년 7월 23일 화요일

• 어노테이션 변수에 기본값 지정public @interface FirstAnno { public int value() default 0; public String weekday();}

@FirstAnno(weekday="화요일")private String name;

13년 7월 23일 화요일

어노테이션의 어노테이션

13년 7월 23일 화요일

• 이건 또 무슨 Class의 클래스 같은 소리?

어노테이션의 어노테이션

13년 7월 23일 화요일

• 이건 또 무슨 Class의 클래스 같은 소리?

• 어노테이션 인터페이스 정의에 붙이는어노테이션을 말함

어노테이션의 어노테이션

13년 7월 23일 화요일

• 이건 또 무슨 Class의 클래스 같은 소리?

• 어노테이션 인터페이스 정의에 붙이는어노테이션을 말함

• Meta 어노테이션이라고 함

어노테이션의 어노테이션

13년 7월 23일 화요일

• 이건 또 무슨 Class의 클래스 같은 소리?

• 어노테이션 인터페이스 정의에 붙이는어노테이션을 말함

• Meta 어노테이션이라고 함

• @Target,@Retention,@Documented,@Inherited 하나씩 알아봅시다.

어노테이션의 어노테이션

13년 7월 23일 화요일

@Target

• 어노테이션이 적용될 타입을 지정@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE})public @interface FirstAnno { public int value() default 0; public String weekday();}

13년 7월 23일 화요일

• ElementType.TYPE: 클래스에 적용하는 어노테이션으로 설정

• ElementType.METHOD: 메서드에 적용하는 어노테이션으로 설정

• ElementType.CONSTRUCTOR:생성자에 적용하는 어노테이션으로 설정

• ElementType.ANNOTATION_TYPE:어노테이션에 적용하는 어노테이션으로 설정

13년 7월 23일 화요일

• ElementType.FIELD: 필드에 적용하는 어노테이션으로 설정

• ElementType.PARAMETER: 매개변수에 적용하는 어노테이션으로 설정

• ElementType.LOCAL_VARIABLE:지역변수에 적용하는 어노테이션으로 설정

• ElementType.PACKAGE:패키지에 적용하는 어노테이션으로 설정

13년 7월 23일 화요일

• 필드에만 적용할 어노테이션으로 지정@Target(ElementType.FIELD)public @interface FirstAnno { public int value() default 0; public String weekday();}

13년 7월 23일 화요일

• 어노테이션이 언제까지 유효할 지 설정

• @Retention(RetentionPolicy. ?)

@Retention

Source Code

Compile Runtime

13년 7월 23일 화요일

• RetentionPolicy.SOURCE: 소스코드 상에서만 유효함

• RetentionPolicy.COMPILE: 컴파일 단계까지 유효함

• RetentionPolicy.RUNTIME:프로그램이 실행 중(런타임)일 때도 유효함

13년 7월 23일 화요일

• JavaDoc으로 출력 시 어노테이션 정보를 출력할 것인지를 설정

• @Documented가 적용되어있는 어노테이션은 Java Doc에서도 표현됨

• 없으면 해당 어노테이션은 표현되지 않음

@Documented

13년 7월 23일 화요일

@Inherited

• 하위(자식) 클래스에서 어노테이션을 유지할 것인지를 결정

• @Inherited가 적용되어 있는 경우 하위 클래스에서도 동일하게 어노테이션이 적용됨

• @Retention(RetentionPolicy.RUNTIME)이 함께 적용되어야 의미가 있음

13년 7월 23일 화요일

안드로이드 스터디 하다가

왜?

Reflection과 Annotation을?

13년 7월 23일 화요일

btnAdd = (Button)findViewById(R.id.wl_btnAddWishItem);etItemName = (EditText)findViewById(R.id.wl_etWishItemName);lvItems = (ListView)findViewById(R.id.wl_lvItems);

@ViewByIdprivate Button btnAdd;

@ViewByIdprivate EditText etItemName;

@ViewByIdprivate ListView lvItems;

13년 7월 23일 화요일

룰을 정하자

• @ViewById 에 값을 넘겨주지 않으면필드의 이름을 ID로 간주하자

• @ViewById(R.id.xxx) 처럼ID를 직접 넘겨줄 수 있다.

• So Simple!그렇지만 구현은.. @(#@*!&%

13년 7월 23일 화요일

@ViewById 구현

13년 7월 23일 화요일

package yapp.aa.annotation;

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;

/** * View 클래스의 findViewById 메서드를 대체하기 위한 어노테이션 <p> * * case 1.value 값을 전달받는 경우 그 값을 ID로 사용 </br> * case 2.value 값을 전달받지 않는 경우 어노테이션이 적용된 필드의 이름을 ID로 사용</br> * @author 이준영 * */@Target(ElementType.FIELD) // 멤버 변수(필드)에만 적용하도록 함@Retention(RetentionPolicy.RUNTIME) // 런타임에 유효하도록 함public @interface ViewById { /** * 뷰의 ID 저장 * @return 뷰의 ID */ public int value() default -1;}

13년 7월 23일 화요일

package yapp.aa.annotation;

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface ViewById { public int value() default -1;}

주석 빼면? 사실 몇 줄 안되는 어노테이션

13년 7월 23일 화요일

ViewByIdResolver Class

리플렉션을 통해 Activity의 필드 중@ViewById 어노테이션이 적용된 필드에

뷰를 찾아 설정해주는 역할을 수행

13년 7월 23일 화요일

어떻게 해야할까?

• Reflection을 통해 액티비티의 필드를 가져옴getDeclaredFields()

• 가져온 필드에 적용된 어노테이션을 가져옴getAnnotation(ViewById.class)

• 어노테이션이 적용되었다면 값을 가져옴null인 경우는 어노테이션이 적용되지 않은 필드

• value가 -1인지, 지정된 값인지에 따른 처리

• 액티비티에서 뷰를 찾아서 필드에 값을 설정

13년 7월 23일 화요일

이런 모양으로 시작해봅시다public class ViewByIdResolver{ public static void resolve(Activity activity) { }}

13년 7월 23일 화요일

ㄱㄱ

13년 7월 23일 화요일

더 많은 것들을 할 수 있지 않을까?

13년 7월 23일 화요일

findViewById 말고?

• setOnClickListener?

• 여기서 숙제 @Click 만들어보기(사실 검색해도 나오긴 합니다 :D )

• 요점은 고민해보기

13년 7월 23일 화요일