관리 메뉴

bright jazz music

제네릭 사용 연습: 01. 제네릭의 개념 본문

JAVA

제네릭 사용 연습: 01. 제네릭의 개념

bright jazz music 2022. 11. 2. 16:52

아래의 페이지를 참고하였다.

http://www.tcpschool.com/java/java_generic_concept

 

 

Generic

 

  • 자바에서의 제네릭은 데이터의 타입을 일반화 한다는 것을 의미(generalize)
  • 제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법

 

 

  • 컴파일 시에 미리 타입검사를 수행하면 아래와 같은 장점을 가진다.

1. 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있다.

2. 반환값에 대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있다.

 

JDK 1.5 이전에는 여러 타입을 사용하는 대부분의 클래스나 메소드에서, 파라미터나 반환 값으로 Object를 사용했다.

이 경우 반환된 Object 객체를 다시 원하는 타입으로 타입 변환해야 하며, 이 과정에서 오류 발생 가능성도 존재한다.

 

하지만 제네릭을 사용하면 컴파일 시에 미리 타입이 정해지므로 타입 검사나 타입 변환과 같은 번거로운 작업을 생략할 수 있다.

 

제네릭은 클래스와 제네릭 메소드는 다음과 같은 방법으로 선언할 수 있다.

class MyArray<T> {
	T element;
    void setElement(T element){this.element = element;}
}
  • T는 타입변수(type variable)이며 임의의 참조형 타입을 의미한다.
  • 꼭 T뿐만 아니라 어떠한 문자를 사용해도 상관 없다. 여러개의 타입 변수는 쉼표,로 구분하여 명시 가능하다.
  • 타입변수는 클래스에서뿐만 아니라 메소드의 파라미터나 반환값으로 사용할 수도 있다.

 

위와 같이 선언된  제네릭 클래스를 생성할 때에는 타입 변수 자리에 실제 사용할 타입을 명시해야 한다.

MyArray<Integer> myArr = new MyArr<Integer>();

위 예시는 MyArray 클래스에 사용될 타입 변수로 Integer 타입을 사용한다.

제네릭 클래스를 생성할 때 실제 사용할 타입을 명시하면, 정의된 타입변수가 아래와 같이 명시된 실제 타입으로 변환되어 처리된다.

class MyArray<Integer> {
	Integer element;
    void setElement(Integer element){this.element = element;}
}

 

그런데 왜 아래와 같이는 선언할 수 없는 것일까?

MyArray<int> myArr = new MyArr<int>();
  • 자바에서 타입 변수 자리에 실제 사용할 타입을 명시하는 경우, 기본 타입(또는 원시타입, primitive type)을 바로 사용할 수는 없기 때문이다. 기본타입 대신에 그것을 객체화 한 래퍼(wrapper) 클래스를 사용해야 한다.

 

 

제네릭 클래스 사용 예시

: Cat과 Dog 클래스는 LandAnimal 클래스를 상속하므로 AnimalList<LandAnimal>에 추가할 수 있다.

그러나 Sparrow클래스는 타입이 다르므로 추가할 수 없다.

package com.example.demospring.testFile;

import java.util.ArrayList;
import java.util.Iterator;

class LandAnimal {
    public void crying() {
        System.out.println("## Land Animal");
    }
}

class Cat extends LandAnimal{
    @Override
    public void crying() {
        //super.crying();##Land Animal
        System.out.println("## cat cat");
    }
}

class Dog extends LandAnimal{
    @Override
    public void crying() {
        System.out.println("## dog dog");
    }
}

class Sparrow{
    public void crying(){
        System.out.println("## chup chup");
    }
}

///////////////////제네릭 클래스와 제네릭 메소드///////////////////

class AnimalList<T>{
    ArrayList<T> animalList = new ArrayList<T>();

    void add(T animal) { animalList.add(animal);}  //리스트에 추가
    T get(int index){ return animalList.get(index);} //인덱스에 맞는 객체 반환
    boolean remove(T animal){ return animalList.remove(animal);} //파라미터명과 일치하는
    int size(){ return animalList.size();}

}



public class TestGeneric {
    public static void main(String[] args){
        AnimalList<LandAnimal> landAnimalList = new AnimalList<>();

        landAnimalList.add(new LandAnimal());
        landAnimalList.add(new Cat());
        landAnimalList.add(new Dog());
        //landAnimalList.add(new Sparrow()); 오류발생
        
        //전통적 for문
        System.out.println("<conventional for-loop>");
        for (int i=0; i< landAnimalList.size(); i++) {
            landAnimalList.get(i).crying();
        }
        
        //enhanced for-loop
        System.out.println("\n<enhanced for-loop>");
        for (LandAnimal landAnimal : landAnimalList.animalList) {
            landAnimal.crying();
        }
        
        //이터레이터 사용
        Iterator<LandAnimal> iterator = landAnimalList.animalList.iterator();
        System.out.println("\n<iterator>");
        while (iterator.hasNext()){
            LandAnimal landAnimal = iterator.next();
            landAnimal.crying();
        }


    }
}

/*
<conventional for-loop>
## Land Animal
## cat cat
## dog dog

<enhanced for-loop>
## Land Animal
## cat cat
## dog dog

<iterator>
## Land Animal
## cat cat
## dog dog


 */

 

참고:

위처럼 선언된 제네릭 타입들은 실제로는 컴파일 시 자동으로 타입이 변환된다. 따라서 코드 내의 모든 제네릭 타입은 제거되며 컴파일 된 class 파일에는 어떠한 제네릭 타입도 남지 않게 된다.

Comments