제네릭(Generics)이란?
: 특정 타입만 다루지 않고, 여러 종류의 타입으로 변신할 수 있도록 클래스나 메소드를 일반화시키는 기법입니다.
재네릭의 장점
1. 타입 안정성을 제공해줍니다.
2. 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해 집니다.
- Generics 사용하기 이전에 범용적으로 사용할 수 있는 변수로 Object를 배웠습니다. Object여러 참조자료형을 사용해보도록 하겠습니다.
- 자료형
class FruitBox {
Object item;
public void store(Object item)
{this.item = item;}
public Object pullOut()
{return item;}
}
class Apple {
int weight; // 사과의 무게
Apple(int weight)
{this.weight = weight;}
public void showAppleWeight()
{System.out.println("사과의 무게 : " + weight);}
}
class Orange {
int sugarContent; // 당분 함량
Orange(int sugarContent)
{this.sugarContent= sugarContent;}
public void showSugarContent()
{System.out.println("당분 함량 : " + sugarContent);}
}
public class ObjectBaseFruitBox {
public static void main(String[] args) {
Orange orange = new Orange(10);
Apple apple = new Apple(500);
FruitBox orangeBox = new FruitBox();
orangeBox.store(orange);
FruitBox appleBox = new FruitBox();
appleBox .store(apple);
// 1) Object 자료형을 (Apple)강제 변환
Object orangeda = orangeBox.pullOut();
((Orange) orangeda).showSugarContent();
Object appleda= appleBox . pullOut() ;
((Apple)appleda).showAppleWeight();
// 2) 초기화 할때의 값을 Orange로 강제 변환해서 자장
Orange tmpOrange = (Orange)orangeBox.pullOut();
tmpOrange.showSugarContent();
Apple tmpApple = (Apple)appleBox.pullOut();
tmpApple.showAppleWeight();
FruitBox objectBox = new FruitBox();
objectBox.store("사과");
위의 참조자료형들을 Object를 이용하여 강제형변환을 사용하여 원하는 값을 출력할 수 있었습니다. 하지만 여기에 문제 점이 있습니다. 그것은 범용적으로 만드는 것은 좋았는데 잘못된 값을 입력하여도 error 나지 않는다는 문제점이 존재합니다. (범용적인 사용할 수 있지만 자료형에 있어서는 안전하지 않습니다.)
이러한 범용적으로 사용하면서 안정성까지 가질 수 있는 방법 = generics!
Generics
: 하나의 자료형으로 범용적으로 사용고 싶을 때: new 선언시에 자료형을 결정하도록 하여 안정성을 확보합니다.
class FruitBox <T>{
T item;
public void store(T item)
{this.item = item;}
public T pullOut()
{return item;}
}
class Apple {
int weight; // 사과의 무게
Apple(int weight)
{this.weight = weight;}
public void showAppleWeight()
{System.out.println("사과의 무게 : " + weight);}
}
class Orange {
int sugarContent; // 당분 함량
Orange(int sugarContent)
{this.sugarContent= sugarContent;}
public void showSugarContent()
{System.out.println("당분 함량 : " + sugarContent);}
}
위의 참조자료형 정의된 것들중에서 Class FruitBox 에 Object 자리에 < T > 를 넣어서 T에 해당하는 자료형의 이름은 인스턴스를 생성하는 순간에 결정되게 합니다.
public class GenericBaseFruiBox {
public static void main(String[] args) {
FruitBox<Apple> appleBox = new FruitBox<Apple> ();
// new 했을 떄, <T> 로 지정되었던 것이 <Apple>으로 대입해서 사용됩니다.
// 자료형의 type 이 apple로 고정됩니다.
Apple apple = new Apple(700);
appleBox. store(apple);
// appleBox.store("사과")); // error : 자료형이 안정적으로 사용될 수 있게 되었다.
Apple tmpApple = appleBox.pullOut();
tmpApple. showAppleWeight();
FruitBox<Orange> OrangeBox = new FruitBox<Orange> ();
Orange orange = new Orange (7);
OrangeBox.store(orange);
// OrangeBox.store(apple); //자료형이 잘못입력되어 error
Orange tmpOrange = OrangeBox.pullOut();
tmpOrange.showSugarContent();
}
}
< T > 의 자리에 참조변수 이름을 넣어서 인스턴스 생성시 결정된 T의 자료형에 일치 하지 않으면 컴파일 에러가 발생하므로 자료형에 안정적인 구조가 됩니다.
Generics을 통해서 코드 편의성과 자료형의 안정성 모두가 가능해졌습니다.
Generics method )
: 클래스의 메소드만 부분적으로 제네릭화 할 수 있습니다.
class FatherClass{
@Override
public String toString() {
return "classs FatherClass"; }
}
class ChildClass{
@Override
public String toString() {
return "classs ChildClass"; }
}
class InstanceTypeShower {
int showCnt;
InstanceTypeShower(){
showCnt = 0;}
// GenericsMethod (자료형 1개)
public <T>void showInstType2(T inst1) { // 호출하는 순간 자료형으로 대신하겟다.
showCnt++;
System.out.println(inst1);
}
// GenericsMethod (자료형 2개)
public <T,U>void showInstType1(T inst1, U inst2) { // 호출하는 순간 자료형으로 대신하겟다.
showCnt++;
System.out.println(inst1);
System.out.println(inst2);
}
public void showPrintCnt() {
System.out.println("showCnt = " + showCnt);
}
}
- 제네릭 메소드의 호출과정에서 전달되는 인자를 통해서 제네릭 자료형을 결정할 수 있으므로 자료형의 표현은 생략 가능 합니다.
public class IntroGenericMethod {
public static void main(String[] args) {
FatherClass father = new FatherClass();
ChildClass child = new ChildClass();
InstanceTypeShower shower = new InstanceTypeShower();
shower.<FatherClass>showInstType2(father);
shower.showInstType2(father); // <FatherClass> 생략 가능
// shower.<FatherClass>showInstType(child); // error
shower.<ChildClass>showInstType2(child);
shower.showInstType2(child);
// 2개 이상의 자료형 사용이 가능하다.
shower.<FatherClass,ChildClass>showInstType1(father, child);
shower.showPrintCnt();
}
}
매개변수의 자료형 제한)
package Generics;
interface SimpleInterface{
public void showYourName();
}
class UpperClass{
public void showYourAncestor() {
System.out.println("UpperClass");
}
}
class AAA extends UpperClass implements SimpleInterface{
// 2개의 Method를 가지고 있다.
@Override
public void showYourName() {
System.out.println("Class AAA");
}
}
class BBB implements SimpleInterface{
@Override
public void showYourName() {
System.out.println("Class BBB");
}
}
public class BoundedTypeparam {
public static void main(String[] args) {
AAA aaa = new AAA();
BBB bbb = new BBB();
showInstanceAncestor(aaa);
// aaa 는 SimpleInterface를 구현하고 있기 때문에 문제 없다.
showInstanceAncestor(bbb);
// bbb 는 SimpleInterface를 구현하고 있기 때문에 문제 없다.
showInstanceName(aaa);
//showInstanceName(bbb); // error extends UpperClass 하지 않기 때문이다.
}
public static <T extends SimpleInterface> void showInstanceAncestor(T param) {
// SimpleInterface 는 interface 는 implement를 사용해서 구현해야하지만
// Generics 에서 상속의 개념을 넣을 때는 interface와 상속하는 class 모두 extends 사용한다.
param.showYourName();
}
public static <T extends UpperClass> void showInstanceName(T param) {
param.showYourAncestor();
}
}
public static <T extends SimpleInterface> void showInstanceAncestor(T param) {}
extends SimpleInterface의 자녀 class로 상속하고 있는 자료형만 가능합니다.
public static <T extends UpperClass> void showInstanceName(T param) {}
extends UpperClass의 자녀 class로 상속하고 있는 자료형만 가능합니다.
상속의 관계를 이용하여 매개변수의 자료형의 제한을 넣는 것이 가능합니다.
제네릭 메소드와 배열 )
public class IntroGenericArray {
public static void main(String[] args) {
String[] stArr = {"HI.", "I ' m so happy." , "JAva Generic Program."};
showArrayData(stArr);
}
//public static <T>void showArrayData(T arr) {}
T 어떤 자료형이든 상관 없이 입력되는 순간 자료형으로 확정되므로 error가 나타난다.
public static <T>void showArrayData(T[] arr) {
// 입력 받는 참조자료형이 배열이 확신할 때, 배열 형으로 넣어 준다.
for(int i = 0; i <arr.length; i++) {
System.out.println(arr[i]);
}
}
}
기본 자료형의 이름은 제네릭에 사용 불가합니다. Wrapper 클래스를 사용하여 제네릭을 이용할 수 있습니다.
'빅데이터 > JAVA' 카테고리의 다른 글
[JAVA] Thread (0) | 2020.05.19 |
---|---|
[JAVA] 컬렉션 프레임워크 ( Collection Framework ) (0) | 2020.05.18 |
[JAVA] Calendar 클래스, Date 클래스 , Random 클래스 (0) | 2020.05.17 |
[JAVA] Wrapper 클래스 (0) | 2020.05.17 |
[JAVA] Object 클래스 (0) | 2020.05.17 |