diff --git a/_posts/2024-01-31-generics.md b/_posts/2024-01-31-generics.md index 6a07480..1aa158b 100644 --- a/_posts/2024-01-31-generics.md +++ b/_posts/2024-01-31-generics.md @@ -18,7 +18,7 @@ banner: 기본적인 개념에 대해 간단히 알아보고 개인적으로 헷갈렸던 제네릭 메서드와 타입 범위 한정에 대해 주로 알아보겠습니다! -# 제네릭이란 +## 제네릭이란 자바에서 제네릭은 타입 안정성을 위해 jdk 1.5부터 도입된 문법이다. 클래스 내부에서 사용할 데이터 타입을 클래스 내부에서 선언하는 것이 아닌 외부에서 사용자에 의해 지정하는 기법이다. @@ -29,7 +29,7 @@ ArrayList list = new ArrayList<>(); 이처럼 제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입(type)을 파라미터(parameter) 주듯이 외부에서 지정하는 이른바 타입을 변수화 한 기능이라고 이해하면 된다. -# 제네릭 클래스 +## 제네릭 클래스 클래스 선언문 옆에 제네릭 타입 파라미터가 쓰이면, 이를 제네릭 클래스라고 한다. ```java @@ -56,8 +56,8 @@ public class Main { ``` 제네릭 클래스의 타입 파라미터는 해당 클래스를 **인스턴스화 하는 시점**에 입력한 값을 받아와서 해당 파라미터가 지정된 곳으로 전파된다. jdk 1.7 이후부터는 생성자 부분의 제네릭 타입은 생략 가능하다. -# 제네릭의 장점 -## 재사용성 +## 제네릭의 장점 +### 재사용성 ```java ArrayList list1 = new ArrayList(); ArrayList list2 = new ArrayList(); @@ -69,7 +69,7 @@ LinkedList list4 = new LinkedList(); 제네릭을 사용하면 우리가 나중에 어떤 클래스를 작성할 때에도 지원하고자 하는 타입에 따라 모든 별도의 클래스를 만들필요 없이 사용할때 지정해주도록 해서 재사용성을 높일 수 있다. -## 컴파일 타임 타입검사 +### 컴파일 타임 타입검사 제네릭이 없던 jdk 1.5 이전에는 하나의 클래스가 여러 타입을 다루기 위해서 모든 클래스의 조상인 Object 클래스를 인자와 반환값으로 사용했다. 반환된 Object를 원하는 타입으로 사용하기 위해서는 일일이 타입 변환을 해야했고, 그로 인해 런타임 에러가 발생할 가능성이 존재했다. ```java @@ -93,7 +93,7 @@ Apple apple = list.get(0); // 불필요한 캐스팅 제거 제네릭을 사용하면 이런 실수를 사전에 방지할 수 있다. 코드를 실행하기 전 컴파일 타임에 에러를 찾아 알려주기 때문이다. 게다가 타입이 이미 정해져 있기 때문에 불필요하게 형변환을 해줄 필요가 없다. -# 제네릭 메소드 +## 제네릭 메소드 제네릭 메서드란 클래스에 선언한 제네릭과 관계없이(혹은 클래스에서 선언하지 않더라도) 독립적인 제네릭을 메서드의 타입파라미터로 지정하는 메서드를 의미한다. 보통 아래 예시의 get, set 메서드처럼 클래스의 제네릭을 매개변수로 받거나 반환값으로 사용하는 메서드를 제네릭 메서드로 오해하기 쉽다. @@ -151,7 +151,8 @@ public class Main { > 하지만 제네릭 메서드가 꼭 정적 메서드로만 선언되어야 하는 건 아니다. 인스턴스 메서드로 선언한다면 메서드 호출을 위해 클래스의 인스턴스를 생성해서 접근해야겠지만, > 여전히 클래스에 선언된 제네릭(또는 선언되지 않았더라도)과 관계없이 독립적인 타입파라미터를 선언해 활용할 수 있다. -# 제네릭 타입 범위 한정 + +## 제네릭 타입 범위 한정 제네릭을 사용하면 타입을 원하는 대로 자유롭게 지정할 수 있다는 것이 장점이지만 또, 너무 자유롭다는 것이 단점이 될 수도 있다. @@ -214,10 +215,10 @@ super 키워드는 super 뒤에 오는 타입이 최하위 타입으로 한정 이 때 각각의 사과와 딸기는 종류가 다르지만, 둘 다 '과일'로 보고 자료를 조작해야 할 수도 있다. (예로 들면 과일 목록을 뽑는다거나 등등..) 그럴 때 '사과'를 '과일'로 캐스팅 해야 하는데, 과일이 상위 타입이므로 업캐스팅을 해야한다. 이럴 때 쓸 수 있는 것이 바로 super이다. -## 와 < K extends E> 차이 +### 와 < K extends E> 차이 위 주석에서 보다시피 ``````와 ``````가 타입을 한정하는 범위는 똑같은데 어떤 차이가 있는지 궁금할 수 있다. 차이점은 K는 특정 타입으로 지정이 되지만, ?는 타입이 지정되지 않는다는 의미다. 즉, K extends E는 타입 지정이 필요한 제네릭 클래스를 선언할때 사용하고 ? extends E는 이미 만들어진 제네릭 클래스를 매개변수로 받거나 반환타입을 받을때 사용한다고 보면 된다. -## 재귀적 타입 한정 +### 재귀적 타입 한정 재귀적 타입 한정이란 자기 자신이 들어간 표현식을 사용하여 타입 매개변수의 허용 범위를 한정 시키는 것을 말한다. 실무에선 주로 Comparable 인터페이스와 함께 쓰인다. 예를 들어, 다음과 같이 ```>``` 제네릭 E의 타입 범위를 Comparable 로 한정한다는 E를 중첩시킨 표현식을 사용할수 있는데, 이 말은 '타입 E는 자기 자신을 타입으로 구현한 Comparable 구현체로 한정' 한다는 뜻이다.