반응형
자바에서 제네릭(generic)이란 데이터 타입을 일반화한다는 것을 의미합니다. 제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법입니다. 이렇게 컴파일 시에 미리 타입 검사를 수행하면 다음과 같은 장점을 가집니다.
- 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있습니다.
- 반환값에대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있습니다.
제네릭의 생성 및 선언
자바에서 제네릭은 클래스와 메소드에서만 다음과 같은 방법으로 선언할 수 있습니다.
class MyArray<T>{
T element;
void setElement(T element){this.element = element;}
T getElement(){return element;}
}
위의 예제에서 사용된 T를 타입 변수(type variable)이라 하며, 임의의 참조형 타입을 의미합니다.
꼭 'T' 뿐만 아니라 어떤 문자를 사용해도 상관 없고, 여러개의 타입 변수는 쉼표(,
) 로 구분해 명시할 수 있습니다.
타입 변수는 클래스에서뿐만 아니라 메소드의 매개 변수나 반환값으로 사용할 수 있습니다.
위와 같이 선언된 제네릭 클래스를 생성할 때는 타입 변수 자리에 사용할 실제 타입을 명시해야합니다.
MyArray<Integer> myArr = new MyArray<Integer>();
위의 예제는 MyArray 클래스에 사용된 타입 변수로 Integer 타입을 사용하는 예제입니다. 위처럼 제네릭 클래스를 생성할 때, 사용할 실제 타입을 명시하면, 내부적으로 정의된 타입 변수가 명시된 실제 타입으로 변환되어 처리됩니다.
자바에서 타입 변수 자리에 사용할 실제 타입을 명시할 때는 기본 타입을 바로 사용할 수 없고, 반드시 래퍼(Wrapper) 클래스를 사용해야합니다.
제네릭의 제거 시기(이거 질문해야지)
자바 코드에서 선언되고 사용된 제네릭 타입은 컴파일 시 컴파일러에 의해 자동으로 검사되어 타입 변환됩니다. 그리고 코드 내의 모든 제네릭 타입은 제거 되어 컴파일된 class 파일에는 어떤 제네릭 타입도 포함되지 않게 됩니다. 이런식으로 동작하는 이유는 제네릭을 사용하지 않는 코드와의 호환성을 유지하기 위해서 입니다.
예제
package hello.core;
import java.util.ArrayList;
public class GenericExe {
public static void main(String[] args) {
ArrayList<LandAnimal> landAnimals = new ArrayList<>(); // Java SE 7부터 생략가능함.
landAnimals.add(new Cat());
landAnimals.add(new Dog());
landAnimals.add(new LandAnimal());
// landAnimals.add(new Sparrow()); 오류 발생
for (LandAnimal animal : landAnimals
) {
animal.crying();
}
}
}
class LandAnimal {
public void crying() {
System.out.println("귀찮아아");
}
}
class Cat extends LandAnimal {
@Override
public void crying() {
System.out.println("야옹야옹");
}
}
class Dog extends LandAnimal {
@Override
public void crying() {
System.out.println("멍멍");
}
}
class Sparrow {
public void crying() {
System.out.println("짹짹");
}
}
class AnimalList<T> {
ArrayList<T> al = new ArrayList<>();
void add(T animal) {
al.add(animal);
}
T get(int index) {
return al.get(index);
}
boolean remove(T animal) {
return al.remove(animal);
}
int size() {
return al.size();
}
}
바이트 코드
// class version 55.0 (55)
// access flags 0x21
public class hello/core/GenericExe {
// compiled from: GenericExe.java
// access flags 0x1
public <init>()V
L0
LINENUMBER 5 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lhello/core/GenericExe; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x9
public static main([Ljava/lang/String;)V
L0
LINENUMBER 8 L0
NEW java/util/ArrayList
DUP
INVOKESPECIAL java/util/ArrayList.<init> ()V
ASTORE 1
L1
LINENUMBER 9 L1
ALOAD 1
NEW hello/core/Cat
DUP
INVOKESPECIAL hello/core/Cat.<init> ()V
INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
POP
L2
LINENUMBER 10 L2
ALOAD 1
NEW hello/core/Dog
DUP
INVOKESPECIAL hello/core/Dog.<init> ()V
INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
POP
L3
LINENUMBER 11 L3
ALOAD 1
NEW hello/core/LandAnimal
DUP
INVOKESPECIAL hello/core/LandAnimal.<init> ()V
INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
POP
L4
LINENUMBER 13 L4
ALOAD 1
INVOKEVIRTUAL java/util/ArrayList.iterator ()Ljava/util/Iterator;
ASTORE 2
L5
FRAME APPEND [java/util/ArrayList java/util/Iterator]
ALOAD 2
INVOKEINTERFACE java/util/Iterator.hasNext ()Z (itf)
IFEQ L6
ALOAD 2
INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object; (itf)
CHECKCAST hello/core/LandAnimal
ASTORE 3
L7
LINENUMBER 15 L7
ALOAD 3
INVOKEVIRTUAL hello/core/LandAnimal.crying ()V
L8
LINENUMBER 17 L8
GOTO L5
L6
LINENUMBER 18 L6
FRAME CHOP 1
RETURN
L9
LOCALVARIABLE animal Lhello/core/LandAnimal; L7 L8 3
LOCALVARIABLE args [Ljava/lang/String; L0 L9 0
LOCALVARIABLE landAnimals Ljava/util/ArrayList; L1 L9 1
// signature Ljava/util/ArrayList<Lhello/core/LandAnimal;>;
// declaration: landAnimals extends java.util.ArrayList<hello.core.LandAnimal>
MAXSTACK = 3
MAXLOCALS = 4
}
참고 문헌
반응형
'스프링, 자바' 카테고리의 다른 글
자바의 맵 (0) | 2021.02.19 |
---|---|
자바의 애노테이션 (0) | 2021.02.06 |
스프링 핵심 원리 -기본편 (0) | 2021.02.02 |
김영한 강사님의 스프링 입문 나머지 (0) | 2021.01.31 |
회원 관리 예제 - 웹 MVC 개발 (0) | 2021.01.30 |