'Generic'에 해당되는 글 2건

  1. 2017.05.17 제네릭 메소드
  2. 2017.05.16 제네릭 개념 알기

제네릭 메소드

JAVA/JAVA 2017. 5. 17. 17:08 |

제네릭 메소드(Generic method)


제네릭 메소드에 대해 전에 간단하게 포스팅 했었는데 오라클 레퍼런스 설명 기반으로 포스팅하려고 한다.

제네릭 메서드는 타입매개변수를 가진 메소드이다. 제네릭타입을 선언하는 것과 비슷하지만 타입매개변수의 스코프는 매서드로 제한된다.(?)


제네릭 메서드 문법은 return 타입 전에 <>사이 타입에 타입매개변수를 표기한다.

static generic 메서드를 위해 타입매개변수는 반드시 메서드의 return타입 이전에 위치해야한다.


아래의 코드를 보면

Util 클래스는 두 Pair 객체를 비교하는 generic 메소드를 포함하고 있다. 




public class Util {
    public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}

public class Pair<K, V> {

    private K key;
    private V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public void setKey(K key) { this.key = key; }
    public void setValue(V value) { this.value = value; }
    public K getKey()   { return key; }
    public V getValue() { return value; }
}

두 메소드를 호출한 문장은 아래와 같다.

Pair<Integer, String> p1 = new Pair<>(1, "apple"); Pair<Integer, String> p2 = new Pair<>(2, "pear"); boolean same = Util.<Integer, String>compare(p1, p2);


Util.<Integer, String>compare(p1, p2);

<>안에 타입을 명시하여 타입인자는 컴파일러가 타입 추론한다. <>안에 타입 명시하지 않고 generic 메서드가

아닌 일반 메서드를 호출해도 타입추혼이 이루어 진다. 




'JAVA > JAVA' 카테고리의 다른 글

jvm 메모리 구조  (0) 2019.04.22
[객체지향] JAVA SOLID 원칙  (0) 2019.02.23
제네릭 개념 알기  (0) 2017.05.16
다형성  (0) 2015.08.28
클라이언트 ip 구하기  (0) 2015.08.13
Posted by 양승아
:

제네릭 개념 알기

JAVA/JAVA 2017. 5. 16. 15:29 |

java 재네릭


재네릭은 클래스 내부에서 사용할 데이터타입을 외부에서 지정하는 기법을 의미한다.

데이터타입을 외부에서 지정하면 장점뭘까?

메소드 선언에 사용되는 파라미터 형식처럼, 타입 파라미터는 다른 입력값을 같은 코드를 재사용 할 수 있는 방법을 제시한다.

다른점은 형식 파라미터는 값이 아니라 입력이다.

타입파라미터는 타입이 입력!


제네릭 없이 캐스팅이 필요한 코드

List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0);


제네릭을 사용하여 코드 작성시,캐스팅이 필요 없어진다.

List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); // no cast


제네릭을 사용함으로써 일반적인 알고리즘을 구현하도록 지원한다.

generics를 사용하면서 다양한 타입들의 콜렉션을 사용할 수 있고 더 안정적이고 읽기 쉬운 코드를 일반적인 알고리즘으로 구현할 수 있다.


좀더 자세히 알아보자.

아래의 코드를 살펴보자.

class Person<T>{
 public T info; 
}
 public class GenericDemo{
  
  public static void main(String[] arge){
    Person<String> p1 = new Person<String>();
    Person<StringBuilder> p2 = new Person<StringBuilder>();
  } 
}



데이터 타입 결과는 

p1.info = String

p2.info = StringBuilder


각각의 인스턴스를 생성할 때 사용한 <> 사이에 어떤 데이터 타입을 사용했느냐에 달려있다.


클래스 선언부

public T info;


클래스 필드 info의 데이터 타입은 T로 되어있다. 실제로 T라는 데티어 타입은 존재하지 않는다.

이값은 아래 코드의 T에서 정해진다.


제너릭 클래스 선언부

class Person<T>{


제네릭 클래스의 인스턴스 생성부

Person<String> p1 = new Person<String>();

제네릭 클래스의 인스턴스 생성시 <String> 으로 지정하면서 제네릭 T info는 String info 가 된다.


재네릭 사용하는 이유


class StudentInfo{
    public int grade;
    StudentInfo(int grade){ this.grade = grade; }
}

class StudentPerson{
    public StudentInfo info;
    StudentPerson(StudentInfo info){ this.info = info; }
}

class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class EmployeePerson{
    public EmployeeInfo info;
    EmployeePerson(EmployeeInfo info){ this.info = info; }
}
public class GenericDemo {
    public static void main(String[] args) {
        StudentInfo si = new StudentInfo(2);
        StudentPerson sp = new StudentPerson(si);
        System.out.println(sp.info.grade); // 2
        EmployeeInfo ei = new EmployeeInfo(1);
        EmployeePerson ep = new EmployeePerson(ei);
        System.out.println(ep.info.rank); // 1
    }
}


위 코드를 보면 StudentPerson와 EmployeePerson가 중복되는 클래스이다.

f(x) = x 함수 클래스로 x 매개변수를 제네릭 클래스로 구현하여 StudentPerson와 EmployeePerson 클래스중복을 제거해보자.


class StudentInfo{
    public int grade;
    StudentInfo(int grade){ this.grade = grade; }
}
class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T>{
    public T info;
    Person(T info){ this.info = info; }
}
public class GenericDemo {
    public static void main(String[] args) {
        Person<EmployeeInfo> p1 = new Person<EmployeeInfo>(new EmployeeInfo(1));
        EmployeeInfo ei1 = p1.info;
        System.out.println(ei1.rank); // 성공
         
        Person<String> p2 = new Person<String>("부장");
        String ei2 = p2.info;
        System.out.println(ei2.rank); // 컴파일 실패
    }
}

 

기본 데이터 타입과 제네릭

제네릭은 참조 데이터 타입에 대해서만 사용할 수 있다. 기본 데이터 타입에서는 사용할 수 없다. 따라서 아래 코드의 int는 오류난다.

int . char, double ..등등 은 기본데이터로 사용할 수 없다. int 대신 integer 로 대신하여 사용할 수 있다.

class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T, S>{
    public T info;
    public S id;
    Person(T info, S id){ 
        this.info = info; 
        this.id = id;
    }
}
public class GenericDemo {
    public static void main(String[] args) {
        Person<EmployeeInfo, int> p1 = new Person<EmployeeInfo, int>(new EmployeeInfo(1), 1);
    }
}
 

복수 제네릭

클래스 내에서 여러개의 제네릭을 필요로 하는 경우 아래의 코드를 참조하자.

class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T, S>{
    public T info;
    public S id;
    Person(T info, S id){ 
        this.info = info;
        this.id = id;
    }
}
public class GenericDemo {
    public static void main(String[] args) {
        EmployeeInfo e = new EmployeeInfo(1);
        Integer i = new Integer(10);
        Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
        System.out.println(p1.id.intValue());
    }
}
 

재네릭 메소드 사용

class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
}
class Person<T, S>{
    public T info;
    public S id;
    Person(T info, S id){ 
        this.info = info;
        this.id = id;
    }
    public <U> void printInfo(U info){
        System.out.println(info);
    }
}
public class GenericDemo {
    public static void main(String[] args) {
        EmployeeInfo e = new EmployeeInfo(1);
        Integer i = new Integer(10);
        Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
        p1.<EmployeeInfo>printInfo(e);
        p1.printInfo(e);
    }
}
 
재네릭 인스턴스 생략 가능하다. 아래와 같이 p1,p2 모두 정상적으로 생성된다.
Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
Person p2 = new Person(e, i);


extends 로 재네릭으로 올 수 있는 데이터 타입을 특정 클래스의 자식으로 제한할 수 있다.

extends는 상속 관계인 클래스 뿐만 아니라 구현(implements)의 관계에서도 사용할 수 있다.

interface Info{
    int getLevel();
}
class EmployeeInfo implements Info{
    public int rank;
    EmployeeInfo(int rank){ this.rank = rank; }
    public int getLevel(){
        return this.rank;
    }
}
class Person<T extends Info>{
    public T info;
    Person(T info){ this.info = info; }
}
public class GenericDemo {
    public static void main(String[] args) {
        Person p1 = new Person(new EmployeeInfo(1));
        Person<String> p2 = new Person<String>("부장");
    }
}



제네릭에 대해 기본적인 개념만 살펴보았다.


'JAVA > JAVA' 카테고리의 다른 글

[객체지향] JAVA SOLID 원칙  (0) 2019.02.23
제네릭 메소드  (0) 2017.05.17
다형성  (0) 2015.08.28
클라이언트 ip 구하기  (0) 2015.08.13
java foreach 반복문  (0) 2015.08.13
Posted by 양승아
: