:데이터의 타입을 외부에서 사용자에 의해 지정되는 것
List<Integer> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();
ㄴ 여기서 처럼 꺽쇠 안에 클래스 타입이 명시된 패턴
1. 클래스에 제네릭파라미터 선언
class Sample<T> {
private T anonyTypeData;
}
2. 메소드에 제네릭 파라미터 선언
/**
*
* @param supplier java8의 함수형 인터페이스중 하나로 구현시점에 리턴값을 결정하며 타입이 정의된다.
* @param <T> test2메소드 호출시 전달받을 타입 파라미터로 supplier의 반환타입이자 test2의 반환타입으로 정의한다.
* @return
*/
public <T> T test2(Supplier<T> supplier){
System.out.println("supplier 인터페이스의 반환타입에 따라서 test2의 반환타입이 결졍된다.");
return supplier.get();
}
```
파라미터 타입이나 리턴 타입에 대한 정의를 외부로 미룬다
>> 타입 안정성 제공 ( 컴파일러가 타입 확인후 검증 가능 >> 오류 방지 )
유연성&코드 재사용성 : 다양한 상황에서 코드 재사용 가능
//제네릭 파라미터 사용 코드
// @param <T> 클래스 초기화 시 한 가지의 클래스 타입을 제네릭 파라미터로 받는다
class Sample<T> {
private T data; // 데이터의 타입은 제네릭 T
//@param data 파라미터 타입은 클래스 초기화 시 지정한 타입과 동일하다.
public void setData(T data){
this.data = data;
}
// @return 리턴 타입은 클래스 초기화 시 지정한 타입과 동일하다.
public T getData(){
return data;
}
}
: 제네릭 타입으로 어떤 클래스를 전달했냐에 따라서 메소드의 파라미터, 혹은 리턴타입이 제네릭 파라미터로 전달받은 클래스 타입으로 유연하게 변함
setData메소드나 getData메소드에 여러가지 타입을 이용할 수 있지만, 제네릭 파라미터에 의해 타입이 고정되기 때문에 안정성이 확보
//제네릭 안썼으면
class AnotherSample {
private Object data;
// @param data 모든 타입을 파라미터로 받기위해 파라미터 타입을 최상위 객체인 Object로 정의한다.
public void setData(Object data){
this.data = data;
}
public Object getData(){
return data;
}
}
vvvvvvvvvvvvvvvvvvvvvvvvvvvv코드 호출 이렇게 정신없고 신경써야하는 코드탄생
Sample<String> sample = new Sample<>();
sample.setData("test");
String s = sample.getData();
AnotherSample integerSample = new AnotherSample();
integerSample.setData(1);
int a = (int) integerSample.getData();
AnotherSample stringSample = new AnotherSample();
stringSample.setData("test");
String b = (String) integerSample.getData();
런타임 환경에 아무런 영향이 없는 컴파일 시점의 전처리 기술
>> 런타임 타입 에러를 컴파일 과정에 검출가능
public <P, R> R test(P p, Function<P, R> function){
return function.apply(p);
}
class AnonyMap<K, V> implements Map<K, V>{
....
}
/*
* @param p Function 메소드에서 소비될 P타입의 인자이다.
* @param function Function 제네릭 인자의 첫번째 타입의 파라미터를 소비하여 두번째 타입의 리턴값을 반환한다.
* @param <P> Function 메소드의 소비 파라미터 타입으로 정의한다.
* @param <R> Function 메소드의 리턴 타입으로 정의한다. test메소드의 리턴타입으로 정의한다.
* @return
*/
와일드 카드란 ? 제네릭에서 사용되는 문법적 요소 중 하나로 제네릭 타입에 대해 특정 타입을 지정하지 않고 더 유연하게 다양한 타입을 다룰 수 있도록 하는 기능<?>
@Test
public void test(){
List<String> example = new ArrayList<>();
method1(example); // 제네릭 타입이 일치하지 않기 때문에 컴파일 에러 발생
method2(example); // 모든 제네릭 타입을 허용하기 때문에 컴파일 에러 없음
}
public void method1(List<Object> param){ // List의 제네릭타입으로 Object만 허용한다.
// ...
}
public void method2(List**<?>** param){ // List의 제네릭타입으로 모든 타입을 허용한다.
// ...
}
타입 파라미터 : 상한선 - extends
<T extends 상위타입> : 제네릭 클래스/메소드 생성시 타입의 상한선 지정
와일드카드<?> : 상한선 - extends , 하한선 super
: A 자식 클래스까지만 가능 : B 조상 클래스만 가능
Swift 에서도 Generic 이 있는데 비슷한 역할을 하는군요!
Java 언어를 잘 모르지만 그래도 잘 읽을 수 있었습니다! 다음에도 좋은 글 부탁드려요~