티스토리 뷰
<참고 자료>
☕ 자바 제네릭(Generics) 개념 & 문법 정복하기
제네릭 (Generics) 이란 자바에서 제네릭(Generics)은 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법을 의미한다. 객체별로 다른 타입의 자료가 저장될 수 있도록 한다. 자바에서 배
inpa.tistory.com
자바 [JAVA] - 제네릭(Generic)의 이해
정적언어(C, C++, C#, Java)을 다뤄보신 분이라면 제네릭(Generic)에 대해 잘 알지는 못하더라도 한 번쯤은 들어봤을 것이다. 특히 자료구조 같이 구조체를 직접 만들어 사용할 때 많이 쓰이기도 하고
st-lab.tistory.com
제네릭이란?
클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법을 의미한다.
외부에서 지정을 통해 객체별로 다른 타입의 자료가 저장될 수 있도록 한다.
ArrayList<String> list = new ArrayList<>();
<>가 제네릭이다.
<>안에는 타입명을 기재한다.
위 코드의 경우 String 타입으로 지정되어 문자열 데이터만 리스트에 저장 가능하게 된다.
변수 선언할 때 변수 타입 정해주듯이 객체 타입을 정해주는 것이라고 생각하면 쉽다.
<>는 다이아몬드 연산자라고 한다.
<> 안에 식별자 기호를 지정함으로써 파라미터화 할 수 있다.
메소드가 매개변수를 받아 사용하는 것과 비슷하다고 하여 타입 매개변수(parameter)/타입 변수라고 부른다.
=> 매개변수를 받아 타입을 지정한다!
제네릭은 아래 타입들이 쓰인다.
꼭 이렇게 사용하라는 법은 없지만 널리 이렇게 쓰이고 있다. >> 암묵적 룰임.
타입 | 설명 |
<T> | Type |
<E> | Element |
<K> | Key |
<V> | Value |
<N> | Number |
<S, U, V> | 2번째, 3번째, 4번째에 선언된 타입 |
class Zoo<T>{
ArrayList<T> animals = new ArrayList<>();
public void feed(T food) {
animals.add(food);
}
}
public class Test01 {
public static void main(String[] args) {
Zoo<String> zoo1 = new Zoo<>();
zoo1.feed("바나나");
System.out.println(zoo1.animals.get(0));
}
}
위와 같은 코드 예시가 있다고 하자.
Zoo 클래스를 보면 T를 통해 제네릭 클래스가 만들어져 있다.
main에서 Zoo<String> zoo1 = new Zoo<>();이라고 지정해주고 싶은 타입명인 String을 할당해주면 제네릭 클래스 선언문 부분으로 가서 T가 지정된 타입으로 모두 변환되어 클래스 타입이 지정되게 된다.
즉, T라고 된 부분이 모두 String 타입으로 지정된다.
T타입으로 전파된다고 하여 제네릭 타입 전파가 이루어진다.
이를 전문 용어로는 구체화라고 한다.
타입 파라미터 생략
Zoo<String> zoo1 = new Zoo<String>();
Zoo<String> zoo1 = new Zoo<>();
둘 다 가능하다.
왼쪽 부분에서는 꼭 지정을 해줘야 하지만 오른쪽 생성자 부분에서는 제네릭을 지정해 줄 필요가 없다.
즉, 생략이 가능하다.
타입 파라미터 할당 가능 타입
Reference 타입만 할당이 가능하다. 자바의 원시 타입인 int, double, byte 등은 제네릭 타입 파라미터로 넘길 수 없다.
int, double, byte와 같이 기본적으로 있는 것을 Integer, Double, Byte 등과 같은 클래스로 만들어 놓은 이유도 이러한 제네릭에 사용하기 위함이라고 생각해도 된다.
복수 타입 파라미터
제네릭은 반드시 한 개만 사용해야 하는가?
아니다. 여러개가 필요하면 여러개 지정할 수 있다.
<> 안에 쉼표로 구분하여 지정하면 된다.
package com.test.practice;
import java.util.ArrayList;
class Zoo<T, U>{
ArrayList<T> bears = new ArrayList<>();
ArrayList<U> rabbits = new ArrayList<>();
public void feed(T meat, U vegetable) {
bears.add(meat);
rabbits.add(vegetable);
}
}
public class Test01 {
public static void main(String[] args) {
Zoo<String, String> zoo1 = new Zoo<>();
zoo1.feed("닭", "당근");
System.out.println(zoo1.bears.get(0));
System.out.println(zoo1.rabbits.get(0));
}
}
중첩 타입 파라미터
제네릭 객체를 제네릭 타입 파라미터로 받는 형식도 가능하다.
ArrayList 안에 Set<String>을 원소로 가지게 하고 싶다면 다음과 같이 표현하면 된다.
ArrayList<Set<String>> list = new ArrayList<Set<String>>();
제네릭 주의사항
- 제네릭 타입의 객체 생성 불가
T t = new T(); // 절대 불가 - static 멤버에 제네릭 타입 불가
static 멤버는 클래스가 동일하게 공유하는 변수.
즉, 인스턴스가 생성되기도 전에 미리 타입이 정해져 있어야 하는 부분이다.
따라서, 이후에 지정하는 형태인 제네릭 타입이 불가능한 것이다. - 제네릭 클래스 자체를 배열로 만들기 불가
Zoo<String>[] zoo1 = new Zoo<>[10]; // 불가능
Zoo<String>[] zoo2 = new Zoo[10]; // 가능
제네릭 메소드
class Zoo<T, U> {
public T feed(T x, U y) {
// ...
}
}
위와 같은 형태로 제네릭 클래스에서 제네릭 타입 파라미터를 사용하는 메소드를 제네릭 메소드라고 착각하기 쉽지만 이이것은 그냥 타입 파라미터로 타입을 지정한 메소드이다.
그러면 뭐가 제네릭 메소드야???
메소드 선언부에 T가 아닌 <T>의 형태로 선언되어 있어야 한다.
=> 뭐가 다른 거지..?
아 위에 예시는 클래스를 생성하면서 설정된 타입을 그대로 가져와서 사용할 뿐이지만 제네릭 메소드는 직접 메소드에 설정하는 형식으로 동적으로 타입을 받아온다.
즉, 제네릭 클래스에 정의된 타입 매개변수와 제네릭 메소드에 정의된 타입 매개변수는 별개다.
각각 독립적으로 실행된다.
제네릭 메소드의 제네릭 타입 선언 위치는 메소드 반환 타입 바로 앞이다.
그런데 이때, 메소드를 호출할 때 직접적으로 지정을 안 해주면 클래스 타입 매개변수를 통해 추론하여 지정되게 된다.
즉, 독립적으로 지정해주고 싶다면 꼭 직접적으로 지정을 해줘야 한다.
>> 이 부분은 Inpa Dev 블로그에서 제네릭 메소드 설명 부분을 보면 이해하기 쉽다!! 직접 표시해서 해주셨다.
제네릭 타입 범위 한정
지금 이대로 사용하게 된다면 너무 자유롭다는 단점이 있다.
<T>를 통해 어떤 타입이든 지정해 줄 수 있기 때문이다.
너무 자유로워도 문제가 된다... 이걸 어떻게 해결할 수 있는가?
extends, super, ?를 사용하여 가능하다.
extends
상한 경계
<? super T>
T와 T의 하위 클래스만 허용
super
하한 경계
<? extends T>
T와 T의 상위 클래스만 허용
?
와일드카드
<?>
<? extends Object>와 마찬가지다.
일단 이정도로 정리...
필요하면 추가적으로 다시 정리하겠다.
'Backend > Java' 카테고리의 다른 글
[Java] 람다식, 익명 클래스 (0) | 2025.03.14 |
---|---|
String 클래스 (0) | 2024.09.29 |
공유 참조와 사이드 이펙트, 불변객체 (0) | 2024.09.28 |
동일성과 동등성 (0) | 2024.09.04 |
정적 의존관계 vs 동적 의존관계 (0) | 2024.09.03 |
- Total
- Today
- Yesterday
- nullsafety
- 절대강좌유니티
- 형변환
- 콘솔창
- 공백포함
- 1546
- DART
- 아스키코드
- split
- 문자열 함수
- 백준
- C심화
- sourcetree
- scanf
- 동적할당
- 자료형
- c언어
- 11720
- Unity
- generics
- 미로찾기
- 코뮤니티
- 이미지분류
- Failed to create GICache
- TensorFlow
- 2차원 배열
- 이중포인터
- 1152
- C
- github
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |