2016년 3월 11일 금요일

2016년 3월 8일 화요일

Adapter 패턴 vs. Facade 패턴 vs. Decorator 패턴

1) 어댑터 패턴


1-1. 정의

한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환합니다.
어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있습니다.

1-2. 클래스 어댑터 패턴

단점: 상속(Generalzation)을 활용하기때문에 유연하지 못하다.
장점: 어댑터(Adapter)를 전체를 다시 구현할 필요가 없다.(빠르다)


주의: 클래스 어댑터에서는 다중상속을 이용하기 때문에 자바에서는 쓸 수 없습니다.
쓸수있습니다.(간접적 다중상속 지원)




- 코드


public class Adaptee {
public void specificRequest() {
System.out.println("Adaptee.speificRequest()");
}
}

public interface Target {
public void request();
}

public class Adapter extends Adaptee implements Target {
public void request() {
this.specificRequest(); // 다중상속
}
}

public class Client {
public static void main(String[] args) {
Target target = new Adapter();

target.request();
}
}

- 결과 : "Adaptee.speificRequest()" 출력

1-3. 객체 어댑터 패턴

단점: 어댑터(Adapter)클래스의 대부분의 코드를 구현해야하기때문에 효율적이지 못하다
장점: 구성(Composition)을 사용하기 때문에 더 뛰어나다.(유연하다)


- 코드


public class Adaptee {
public void specificRequest() {
System.out.println("Adaptee.speificRequest()");
}
}

public interface Target {
public void request();
}

public class Adapter implements Target {
Adaptee adaptee = new Adaptee(); // 객체를 만들고

public void request() {
adaptee.specificRequest(); // 객체를 연결한다.
}
}

public class Client {
public static void main(String[] args) {
Target target = new Adapter();

target.request();
}
}



- 결과 : "Adaptee.speificRequest()" 출력


2) 퍼사드 패턴


2-1. 정의

퍼사드는 클래스 라이브러리 같은 어떤 소프트웨어의 다른 커다란 코드 부분에 대한 간략화된 인터페이스를 제공하는 객체이다.

- 퍼사드는 소프트웨어 라이브러리를 쉽게 사용할 수 있게 해준다. 또한 퍼사드는 소프트웨어 라이브러리를 쉽게 이해할 수 있게 해 준다. 퍼사드는 공통적인 작업에 대해 간편한 메소드들을 제공해준다.
- 퍼사드는 라이브러리를 사용하는 코드들을 좀 더 읽기 쉽게 해준다.
- 퍼사드는 라이브러리 바깥쪽의 코드가 라이브러리의 안쪽 코드에 의존하는 일을 감소시켜준다. 대부분의 바깥쪽의 코드가 퍼사드를 이용하기 때문에 시스템을 개발하는 데 있어 유연성이 향상된다.
- 퍼사드는 좋게 작성되지 않은 API의 집합을 하나의 좋게 작성된 API로 감싸준다.

래퍼(wrapper)가 특정 인터페이스를 준수해야 하며, 폴리모픽 기능을 지원해야 할 경우에는 어댑터 패턴을 쓴다. 단지, 쉽고 단순한 인터페이스를 이용하고 싶을 경우에는 퍼사드를 쓴다.


- 퍼사드
퍼사드 클래스는 패키지 1,2,3 및 그림에 나오지 않은 그 밖의 응용 프로그램 코드와 상호 동작한다.
- 클라이언트
패키지 내의 리소스들을 접근하기 위해 퍼사드 클래스를 쓰는 객체들이다.
- 패키지
소프트웨어 라이브러리 / API 집합이다. 퍼사드 클래스를 통해 접근된다.



/* Complex parts */

class CPU {
public void freeze() { ... }
public void jump(long position) { ... }
public void execute() { ... }
}

class Memory {
public void load(long position, byte[] data) {
...
}
}

class HardDrive {
public byte[] read(long lba, int size) {
...
}
}

/* Fa?ade */

class Computer {
public void startComputer() {
CPU cpu = new CPU();
Memory memory = new Memory();
HardDrive hardDrive = new HardDreive();
cpu.freeze();
memory.load(BOOT_ADDRESS, hardDrive.read(BOOT_SECTOR, SECTOR_SIZE));
cpu.jump(BOOT_ADDRESS);
cpu.execute();
}
}

/* Client */

class You {
public static void main(String[] args) throws ParseException {
Computer facade = /* grab a facade instance */;
facade.startComputer();
}
}


3) Adapter 패턴 vs. Facade 패턴 vs. Decorator 패턴 차이점


각 패턴의 용도들을 비교해 차이점을 알아보자 !

* Adapter 패턴 : 한 인터페이스를 다른 인터페이스로 변환 (for 호환성)
인터페이스를 변경해서 클라이언트에서 필요로 하는 인터페이스로 적응시키기 위한 용도.

* Facade 패턴 : 인터페이스를 간단하게 바꿈 (for 간편함)
어떤 서브시스템에 대한 간단한 인터페이스를 제공하기 위한 용도.

* Decorator 패턴 : 인터페이스를 바꾸지 않고 책임(기능)만 추가함 (for 기능 추가)

객체를 감싸서 새로운 행동을 추가하기 위한 용도.

4) 최소 지식 원칙 (Principle of Least Knowledge) 또는 데메테르의 법칙 (Law of Demeter)

- 참고로 둘 다 같은 말이다.
- 정말 친한 친구들하고만 얘기하라.
- 최소 지식 원칙에 따르면 객체 사이의 상호작용은 될 수 있으면 아주 가까운 '친구' 사이에서만 허용하는 것이 좋다 !
- 이를 잘 따르면 여러 클래스들이 복잡하게 얽힌 시스템의 한 부분을 변경했을 때, 다른 부분까지
줄줄이 고쳐야 되는 상황을 미리 방지할 수 있다.

- 이 원칙을 지키기 위한 가이드 라인 : 다음 4 종류의 객체의 메소드만 호출하면 된다.
(1) 객체 자체
(2) 메소드에 매개변수로 전달된 객체
(3) 그 메소드에서 생성하거나 인스턴스를 만든 객체
(4) 그 객체에 속하는 구성요소
구성요소는 인스턴스 변수에 의해 참조되는 객체를 의미. 즉, 'A에는 B가 있다' 관계에 있는 객체.

- 위 가이드 라인에 따르면 다른 메소드를 호출해서 리턴 받은 객체의 메소드를 호출하는 건 바람직하지 않다고 한다.

- 객체들 사이의 의존성을 낮추고, 소프트웨어 관리가 더 용이해질 수는 있으나 단점도 있다.
다른 구성요소에 대한 메소드 호출을 처리하기 위해 'Wrapper' 클래스를 더 만들어야 할 수도 있다.
그러다 보면 시스템이 더 복잡해지면서 개발 시간이 늘어나고 성능 저하를 불러일으키는 요인이 될 것이다.

5) 객체지향의 원칙 

1. 바뀌는 부분은 캡슐화 한다.
2. 상속보다는 구성을 활용한다.
3. 구현이 아닌 인터페이스에 맞춰서 프로그래밍 한다.
4. 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.
5. 클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다(OCP).
6. 추상화된 것에 의존해라. 구상 클래스에 의존해서는 안 된다(의존성 뒤집기 법칙).
7. 친한 친구들하고만 이야기한다(최소 지식 원칙).


6) 총 정리 

- 기존 클래스를 사용하려고 하는데 인터페이스가 맞지 않으면 어댑터를 쓰자.
- 큰 인터페이스 or 여러 인터페이스를 단순화 시키거나 통합시켜야 되는 경우에는 퍼사드를 쓰자.

- 어댑터는 인터페이스를 클라이언트가 원하는 인터페이스로 바꿔주는 역할을 한다.
- 퍼사드는 클라이언트를 복잡한 서브시스템과 분리시켜주는 역할을 한다.

- 어댑터를 구현할 때는 Target 인터페이스의 크기와 구조에 따라 코딩해야 할 분량이 결정된다.
- 퍼사드 패턴에서는 서브시스템을 가지고 퍼사드를 만들고, 실제 작업은 서브클래스에 맡긴다.

- 어댑터 패턴에서는 객체 어댑터 패턴 vs. 클래스 어댑터 패턴(다중상속必)이 있다.
- 어댑터는 다중 어댑터로 만들 수 있고, 퍼사드는 한 서브시스템에 여러 개 만들어도 된다.

- 어댑터, 퍼사드 모두 인터페이스를 바꿔주는데 !
Adapter : 인터페이스를 변환
Facade : 인터페이스를 통합/단순화 시킴
Decorator : 인터페이스를 바꾸지 않고, 객체를 감싸서 새로운 기능을 추가할 수 있다.


*reference

  • http://wiki.gurubee.net/pages/viewpage.action?pageId=1507407#7.%EC%96%B4%EB%8C%91%ED%84%B0%ED%8C%A8%ED%84%B4%EA%B3%BC%ED%8D%BC%EC%82%AC%EB%93%9C%ED%8C%A8%ED%84%B4-33.%EC%98%88%EC%A0%9C%3AXML%ED%8A%B8%EB%A6%AC
  • http://secretroute.tistory.com/entry/Head-First-Design-Patterns-%EC%A0%9C7%EA%B0%95-Adapter-%ED%8C%A8%ED%84%B4%EA%B3%BC-Facade-%ED%8C%A8%ED%84%B4
  • https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%82%AC%EB%93%9C_%ED%8C%A8%ED%84%B4


Share:

logback을 사용해야 하는 이유

“Log4j” (현재는 Apache Logging Service라는 Top Project)는  “Ceki G?lc?“라는
개발자가 최초로 만들었습니다.
“Log4J“는 java world에서 “가장 많이 사용하고 있는 logger“라고 감히 말씀 드릴수 있습니다.

이러한 성공에 힘을 입어 “Ceki G?lc?“는 좀더 “Logger“에 대해서 깊은 프로젝트를 시작했고,
그것이 바로 “SLF4J” 와 “LOGBack” 입니다.

“SLF4J“는 “로깅 구현체“라기 보다는 “Logging Facade” 입니다.
(※ facade pattern 참조)


“일명 창구 일원화” 패턴인데, “SLF4J“의 API를 사용하면, 구현체의 종류와 상관없이
“일관된 로깅 코드“를 작성할 수있으며,  “Apache Commons Logging“를 사용하다가
“Log4J“로 변경을 할 경우 최소한의 수정으로 구현체를 교체 할수 있습니다.

오늘 설명하는 “LOGBack“은이중 하나의 “구현체” 입니다. 그래서 과연
어떤 이점이 있는지 quick 하게 둘러보고자 합니다.

해당 내용은 (Reasons to prefer logback over log4j)의 자료를 참고 했습니다.

(1) Faster implementation

“LOGBack“은 새롭게 작성 한것이 아니라, 오랫동안 검증된 “LOG4J”의 아키텍쳐 기반으로
재작성 되었습니다.
특히 성능은 약 10배 정도 빠르게 개선을 했고, 또한 메모리 점유도 보다 적게 사용을 합니다.
역시 성능에 관련된 얘기 입니다.

(2) Extensive battery of tests

위에서 말씀 드렸듯 “새로운 오픈소스” 이지만 , 이미  “Log4j” 시절 부터 수년간 수 많은 광범위한 테스트
를 진행했고, 더욱더 많은 테스트의 반복 과정을 수행 했습니다.
“Log4j보다 훨씬 뛰어난 가장 큰 이유중 하나“라고 합니다.
그 만큼 “높은 쿼리티“에 대한 자신감을 엿볼수 있습니다.

(3) logback-classic speaks SLF4J natively

“LOGBack“은 크게 3가지 컴포넌트로 구성이 되어 있습니다.
“logback-core“는 말 그대로 핵심 코어 컴포넌트 입니다.
“logback-classic“은 “slf4j“에서 사용이 가능하도록 만든 플러그인 컴포넌트 입니다.
“logback-access“는 사용하는 어플리케이션이 “웹 어플리케이션“일 경우 빛을 바라는
컴포넌트 입니다.” HTTP 요청에 대한 강력한 디버깅 기능을 제공 합니다.”

(4) Extensive documentation

“오픈소스 선택“에 있어서 레퍼런스 메뉴얼은 상당히 중요한 포인트 입니다.
“LOGBack“은 지속적이면서, 상세한 메뉴얼을 제공 합니다.

(5) Configuration files in XML or Groovy

logging 설정에 대한 syntax는 기본적으로 “XML” 형태로 되어 있습니다.
또한 Groovy의 “syntax” 를 지원 합니다.

(6) Automatic reloading of configuration files

개인적으로 호감이 가는 기능중 하나 입니다. 일하는 도메인 마다 틀리겠지만
기본적으로 “운영 서버” 모드에서는 로그레벨을 “WARN” 또는 “ERROR” 입니다.

하지만 만약 운영중에 좀더 상세한 로그를 보기 원할 경우가 있습니다.
예를 들어서 “INFO” 레벨로 변경하는 경우 입니다.

“log4j” 같은 경우는 다음과 같이  “서버를 셧다운 -> 재설정 -> 서버 기동” 의
절차로 진행을 합니다. 즉, 핵심 포인트는 “서버를 재기동” 해야 한다는 것입니다.

이러한 매커니즘은 “내부 스캐닝하는 별도의 쓰레드“가 감지를 하기 때문 입니다.
하지만 이런 “스캐닝 쓰레드”는 메모리에 대한 점유율을 최소화 하며,
심지어 “100개의 쓰레드가 초당 백만 invocation“을 발생해도 시스템에
크게 무리를 주지 않는 다고 합니다.

주로 이런 기능은 “WAS에서 동장하는 웹 어플리케이션“에서 많이 사용이 될듯 합니다.

(7) Graceful recovery from I/O failures

“Log4j” 같은 경우  “JDBC” , “Socket“등 다양한 “Appender“를 지원 합니다.
특히. 대다수의 환경에서는 “File”에 제일 많이 로그를 저장 할 것입니다.

하지만 만약 “파일 서버가 일시적으로 장애가 발생 할경우” , “파일 서버가 복구 될때까지”
“어플리케이션을 중지 시켰다가” 다시 파일 서버가 복구되면, 그때 서버를 재기동 할것 입니다.
하지만 “LOGBack“은 “서버 중지 없이, 이전 시점부터 복구를 graceful “하게 지원을 합니다.

(8) Automatic removal of old log archives

대부분 환경에서는 “하나의 파일”에 기록하는 것이 아니고, “특정 시간” 또는 “특정 파일 사이즈”
로 “Rolling” 해서 “Archiving“을 할 것입니다.

하지만 “Archiving된 로그 파일“을 계속 유지하지 않고, 일정 기간 지나면
“서비스에  부담을 주지 않기 위해서” 파일을 삭제 할것 입니다.

이럴경우 “Crontab” 또는 다른 삭제 스케줄러를 설정 또는 개발을 할것입니다.
“LOGBack“은 “maxHistory“라는 설정 정보를 통해서 주기적으로 “Archive”
파일을 자동 삭제 합니다.
“maxHistory“의 값이 “12“일 경우, “12개월 이후 삭제 하라는” 뜻입니다.

(9) Automatic compression of archived log files

“Archived Log File“를 만들때 비동기적으로 롤링 할 동안
자동 압축을 실행 합니다. 심지어 파일 용량이 커도, 또한
이러한 압축 작업은 어플리케이션을 block 시키지 않습니다.

(10) Prudent mode

만약 하나의 서버에서 “다수의 JVM“이 기동중일 경우 “하나의 파일“에
로그를 수집하려고 할때 사용하는 기능 입니다.

즉, “Log Aggregation” 기능 입니다. 조금만 아이디어를 내면, 매우 유용하게
사용이 가능 합니다.
다만 서로 쓰레드간 writing 할때 경합이 생기기 때문에 대량의 데이터를 사용할때
는 다소 피해야 합니다.

그렇기 때문에 반드시 해당 옵션을 적용시 “LOGBack” 메뉴얼을 참고 하시기 바랍니다.

(11) Lilith

“Lilith“은 “현재 발생하는 로그 이벤트에 대한 상태 정보를 볼수 있도록 지원 하는
뷰어” 입니다.
“log4j“를 지원하는 “chainsaw” 와 비슷한 기능을 합니다. 다만 차이점은 “Lilith”
“Large data“를 지원 합니다.

(12) Conditional processing of configuration files

빌드를 해본 사람이라면 아실듯 합니다. 빌드시 제일 골치가 아픈 것이 “config” 정보 와
“log file path” 입니다.
이유는 어플리케이션이 구동하는 환경이 “로컬, staging, cbt” 마다 틀리기 때문 입니다.
이런점을 해결 하기 위해서 “Maven Filter” 기능을 사용 하거나,  “JVM -D환경변수“를
통해서 각 환경 마다 선택적으로 “log 설정파일“을 선택하도록 구성을 할 것입니다.

“LOGBack“은 이런 이슈를 좀더 “Graceful“하게 지원을 합니다.
“JSTL” 같이 분기 스크립트 (<if>, <then> and <else>)를 제공해서 하나의 파일
에서 다양한 빌드 환경을 제공 하도록 지원을 합니다.

(13) Filters

“Filter” 기능은 “Log4j“에서 지원하는 기능입니다. 주 기능은 “로깅을 남길지 , 말지를”
핸드링 할수 있는 기능 입니다.
좀더 이해를 돕기 위해서 “UseCase“를 설명 드리겠습니다.

만약 “A“라는 사용자에게 비즈니스적으로 문제점이 발견이 되었습니다.
이럴경우는 “logical exception“이기 때문에 원인을 잡기가 쉽지가 않습니다.
또한 현재 “운영 서버“의 “Log LEVEL“이 “ERROR“일 경우 로그를 확인 할수가 없을
것입니다.
더우기 “운영 서버 logical exception“은 “staging” 환경과 데이터가 틀리기 때문에
실제 운영 로그를 확인하지 않고서는 재현을 할수가 없습니다.

그래서 “운영 서버의 로그 레벨“을   “DEBUG“로 수정합니다. 하지만 로그는 보이지만 전체 사용자가
해당이 되기 때문에 로그 데이터를 분석하기가 어렵습니다.
이럴 경우 “Filter“를 사용해서 “다른 사용자“는 “ERROR” 레벨을 유지하고,
“A” 사용자만 “DEBUG“로 설정을 하면, 분석하는데 많은 도움을 받을 수 있습니다.

(14) SiftingAppender

“SiftingAppender“는 “Filter“의 기능과 유사하면서 다른 기능을 제공 합니다.
“로그 파일을 특정 주제별로 분류“를 할 수 있도록 합니다.
예를 들어서 “HTTP Session“별로 로그 파일을 저장한다거나, “사용자별“로 별도의 로그파일을
저장 할 수 있습니다.

(15) Stack traces with packaging data

자바 어플리케이션에서 “Exception“이 발생을 하면 “Stack Trace“를 출력을 합니다.
자바는 “Exception” 정의가 잘되어 있어서 쉽게 “디버깅“을 할 수 있습니다.

하지만 제일 디버깅이 힘든 것중 하나가 “라이브러리에 의한 Exception” 입니다.
이럴 경우 “LOGBack“은 Exception 발생시 참조 했던 외부 라이브러리 버전을
출력하게 해줍니다.

(16) Logback-access, i.e. HTTP-access logging with brains, is an integral part of logback

위에서 언급했듯이 “logback-access“는 “웹 어플리케이션” 사용시 유용한 툴로써 제공 됩니다.
특히나 요새는 전통적인 “HTML” 출력이 아닌 “REST 서버“로써의 역할을 많이 합니다.
이럴 경우 “HTTP 디버깅“을 제공 합니다.

Conclusion

지금 까지 간략하게 “LOGBack” 기능을 살펴 봤습니다.
이외에 유용하고, 멋진 기능들이 많이 있습니다.

“logging“의 중요함은 지나치게 말씀을 드려도 지나치지 않습니다.
특히나 “클라우드 빅데이터” 시대에서 “logger“는 바로 최초 시작점 입니다.

제일 궁금했던 것이 “log4j를 만든 사람이 왜 ? logback를 만들었을까?” 입니다.

개인적 생각은 “log4j“를 “하위 호환성을 유지하면서 큰 리팩토링을 하기에는 다소 부담감”
과 “상용 버전을 위한 비즈니스적 관점“이 아닐까 조심 스럽게 말씀 드리고 싶습니다.

“LOGBack“의 큰 매력은 “Log4J 와 상당히 친숙함” 일것입니다. 이말은 그 만큼 사용하는데
있어서 낯설지 않다는 얘기 입니다.
심지어 “log4j.properties“를 “logback.xml” 설정 파일로 변환하는 “웹 변환기“도 제공 합니다.



또한 “SLF4J“를 지원하기 때문에 마음에 들지 않으면 “언제든지 다른 로거로 swiching“이 가능 합니다.

*reference

  • https://beyondj2ee.wordpress.com/2012/11/09/logback-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-reasons-to-prefer-logback-over-log4j/ (logback을 사용해야하는 이유 )
  • https://beyondj2ee.wordpress.com/2013/11/05/log4j%EC%97%90%EC%84%9C-logback%EC%9C%BC%EB%A1%9C-%EB%A7%88%EC%9D%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EC%85%98-%ED%95%98%EA%B8%B0-migrate-from-log4j-to-logback/ (logback으로 마이그레이션 하기 )
Share:

2016년 3월 7일 월요일

자바 제네릭(Generics)

1) Generics

제너릭 타입(Generic Types)은 주로 자바 컬렉션에서 많이 사용되고 있다. 컬렉션은 자료구조이다. 컬렉션에는 어떤 자료를 담을지 알 수 없으므로 최상위 객체인 Object형태로 저장되고 관리되도록 설계되어 있다. 하지만, 의도하지 않은 자료형이 담기는 경우도 발생하게 된다. 이 때의 오류는 컴파일시에는 알 수가 없고 실행을 시켜보아야만 알 수 있다는 것이 문제점이었다. 제너릭 타입을 사용하면 프로그래머가 원하는 객체의 타입을 명시해서 의도하지 않은 객체는 저장될 수 없도록 컴파일시에 오류를 확인할 수있게 된다.

2) 제너릭클래스 정의하기

제네릭 클래스를 정의하는 방법은 일반적인 클래스를 정의하는 것과 동일하다. 다만, 클래스명 뒤에 <제너릭타입, ...>이라고 덧붙여 준다.


public class Box {
private T t; // T stands for "Type"
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}

3) 제너릭 클래스 선언 / 생성

일반적인 클래스와 동일하게 선언하고 생성할 수 있다. 다만, 클래스명 뒤에 <제너릭타입>을 덧붙여주면 된다.
Box<Integer> integerBox;
integerBox = new Box<Integer>();
제너릭 타입에 사용되는 파라미터
타입 매개변수는 하나의 대문자를 사용한다. 이들은 파일시스템에 실재로 존재하는 것은 아니다. 즉, T.java 라던지 T.class라는 파일은 없다. 타입매개변수를 여러개 사용할 수도 있지만 하나의 선언문에서 두 번 사용될 수는 없다. 즉, Box<T, U>는 가능하지만 Box<T, T>는 안된다.
* E - Element (자바의 컬렉션에서 널리 사용되고 있다.)
* K - Key
* N - Number
* T - Type
* V - Value
S,U,V etc. - 2nd, 3rd, 4th types

4) 제너릭 메서드 / 제너릭 생성자

타입 매개변수가 메서드의 선언 등에 사용될 수도 있다. 단, 매개변수의 범위가 메서드의 블록 이내로 한정된다.



public class Box {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
public static void main(String[] args) {
Box integerBox = new Box();
integerBox.add(new Integer(10));
integerBox.inspect("some text");
}
}



5) 타입 파라미터 제한하기

타입매개변수를 적당히 제한해야 할 경우에는 extends ...를 사용한다. extends 뒤에는 클래스명일 수도 있고 인터페이스명일 수도 있다. 아래의 예에서는 U가 Number의 하위 클래스이어야 한다.



public void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}


여러 조건을 만족시켜야 할 경우에는 &를 사용할 수도 있다.
<U extends Number & MyInterface>
하위타입
이제, 객체지향의 '이다 (is a)'관계를 생각해 볼 때다. Integer는 Object에 할당할 수 있다. '이다'관계에 있기 때문이다. 마찬가지로 Number에 Integer를 할당할 수도 있고, Double을 할당할 수도 있다. 이러한 관계는 제너릭에서도 마찬가지이다.
Box<Number> box = new Box<Number>();
box.add(new Integer(10)); // OK
box.add(new Double(10.1)); // OK
그러나,
public void boxTest(Box<Number> n){
    // method body omitted
}
이 경우에 Box<Integer>와 Box<Double>는 매개변수로 전달되지 않는다. 이것들은 Box<Number>의 하위타입이 아니기 때문이다. 꽤나 논리적인 내용 전개가 필요하지만 뭔말인지 헷갈리므로 그냥 패스~
와일드카드
?는 알 수 없는 타입을 뜻한다.
<?> - 모든 객체 자료형, 내부적으로는 Object로 인식한다.
<? super 객체자료형> - 명시된 객체자료형과 그 상위 객체, 내부적으로는 Object로 인식한다.
<? extends 객체자료형> - 명시된 객체 자료형과 이를 상속한 하위객체, 내부적으로는 명시된 객체 자료형으로 인식한다.

6) 타입제거

제너릭 타입이 인스턴스화 될 때, 컴파일러는 타입파라미터와 관련된 정보를 제거한다. 제너릭을 사용하기 이전의 라이브러리 등과의 호환성을 유지하기 위해서이다.

*reference

  • http://shonm.tistory.com/category/JAVA/%EC%A0%9C%EB%84%A4%EB%A6%AD%20%EA%B4%80%EB%A0%A8%20%EC%A0%95%EB%A6%AC
  • http://ohgyun.com/51 ( 참고 )


Share: