Java/Java 문법
Java 문법 10 (제네릭)
열심히 해
2024. 9. 10. 12:24
- 타입을 유연하게 다루는 제네릭. 중복되거나 필요 없는 코드를 줄여주는 동시에 타입 안정성을 해치지 않는다.
더보기
// 1.제네릭은 클래스 또는 메서드에 사용 가능하다.
// 클래스 이름 뒤에 <>(<>에 들어갈 타입 변수로 T, U, V, E 같은 문자를 사용, 컨벤션)를 사용하여 타입 변수 선언.
// 선언해놓은 타입 변수는 클래스 안에서 특정한 타입이 들어갈 자리에 사용할 수 있다.
// Generic 클래스를 원시 타입이라고 한다.
public class Generic<T> {
// 2. 내부 필드에 T는 String
private T t;
// 3. 메서드의 return 타입도 String
public T get() {
return this.t;
}
public void set(T t) {
this.t = t;
}
public static <Generic> void main(String[] args) {
// 4. 제네릭을 사용한 클래스를 구현하는 부분, Generic<T> 클래스의 T를 어떤 타입으로 사용할지 명시하며 인스턴스를 만든다.
Generic<String> stringGeneric = new Generic<>();
// 5. 위에서 만든 객체를 통해 set 이나 get-`Generic<T> 클래스의 메서드`-을 하게 되면 객체 안에서의 T는 String 이기 때문에 정상 동작하는 것.
stringGeneric.set("Hello World");
String tValueTurnOutWithString = stringGeneric.get();
System.out.println(tValueTurnOutWithString);
}
}
- generic 클래스의 타입 변수를 객체의 static 멤버에 사용할 수 없다 - 타입 변수는 클래스 내부의 인스턴스 변수로 간주되고, 모든 객체에 동일하게 동작해야 하는 static 필드 특성상 사용할 수 없다-. 제네릭 배열을 생성할 수 없다.
- 다수의 타입 변수를 사용할 수 있다.
public class Generic<T, U, E> {
public E multiTypeMethod(T t, U u) { ... }
}
- 다형성 즉 상속과 타입의 관계는 그대로 적용됩니다. 대표적으로 부모 클래스로 제네릭 타입 변수를 지정하고, 그 안에 자식 클래스를 넘기는 것은 잘 동작합니다.
- 와일드 카드를 통한 generic 제한
- <? extends T> : T와 그 자손들만 사용 가능
- <? super T> : T와 그 조상들만 가능
- <?> : 제한 없음
메서드를 스코프로 별도의 제레릭 선언하기.
- 메서드에만 적용되는 제네릭 타입 변수를 선언할 수 있다.
- 제네릭 메소드의 제네릭 타입 변수는 해당 메소드에만 적용되기 때문에 메소드 하나를 기준으로 선언하고 사용할 수 있다.
- 같은 이름의 변수를 사용했다고 해도 제네릭 메소드의 타입 변수는 제네릭 클래스의 타입 변수와 다릅니다.
public class Generic<T, U, E> {
// Generic<T,U,E> 의 T와 아래의 T는 이름만 같을뿐 다른 변수
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
}
자료 구조라는 실존하는 개념을 인터페이스를 통해서 어떻게 자바 내부에 구현했는지, 그리고 그 안에 제네릭은 어떻게 녹아있는지를 살펴보자.
- List는 추상적 자료구조로서 순서를 가지고 있으며, 일렬로 나열한 원소소들의 모임이다. // 순서가 있고, 중복을 허용한다는 점에서 집합(Set)와 구별된다. List 자체는 interface-메서드의 선언이 들어가 있다-다 . 이를 구현한 것이 구체적 자료구조, 하나의 클래스-interface로부터 받은 메서드에 실제로 구현될 로직이 들어가 있다.-로서 ArrayList, LinkedList 이다.
- 배열은 프로그래밍 언어에서 지원하는 자료형 또는 컴퓨터공학에서 사용하는 자료구조의 하나다. 순서대로 번호가 붙은 원소들이 연속적인 형태로 구성되어 있다.
1. List가 interface라는 점을 확인할 수 있고, 메서드에 구현 부분 {}이 없다는 점도 확인 가능하다.
2. List와 ArrayList에서 generic의 사용`<E>`을 확인할 수 있다.
3. ArrayLsit 클래스가 List 인터페이스로부터 implements 하고 있음을 알 수 있다. List 인터페이스의 구현체들은 List의 속성을 가지게 된다.
4. List 인터페이스는 Collection으로부터, ArrayList 클래스는 AbstractList로부터 각각 상속받고 있음을 알 수 있다.
Wrapper 객체
- 원시 타입(기본형 타입)은 값 자체만 의미를 가지며 메모리 비용이 적게 든다.
- 원시 타입을 추상화 시킨 것이 참조형 (Wrapper) 타입이며 메모리 비용이 크다.
- 그렇게 때문에 자바에서는 추상적인 기능을 사용하거나, 기본형 값 대신 객체로 저장해야 하거나, 객체로서의 기능이 필요할 때 원시형 값들을 잠시 객체로 만들어 사용한다.
원시 타입, 참조형 타입으로의 형변환
Integer num = new Integer(17); // Boxing
int n = num.intValue(); // UnBoxing
Character ch = 'X'; // AutoBoxing
char c = ch; // AutoUnBoxing