제네릭 요점 정리

SionBackEnd·2022년 7월 14일
0

자바 스터디

목록 보기
8/21
post-thumbnail

제네릭

이전까지는 우리가 객체를 생성할때 이미 정해진 타입으로 객체를 생성해왔었다. 하지만, 이러한 방식은 우리가 만약 객체의 타입을 미리 정해두지 않으면 코드 작성의 어려움이 생긴다. 그래서 생긴것이 바로 제네릭이다. 제네릭은 주로 클래스에 같이 명시하는데 이때 그 클래스 내부에 로 설정한 데이터 타입이 객체생성시 지정해주는 데이터 타입으로 변하게 된다. 즉 쉽게 말하면 이 T타입은 어떤 타입으로든 변할수 있는 타입이다. 말로 설명하면 어려우니 코드를 보자!

class A <T> {
    private T item;

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}

public class Main {
    public static void main(String[] args) {
        //String 타입
        A<String> a = new A<>();
        a.setItem("String 타입");
        System.out.println(a.getItem());
        //Integer 타입
        A<Integer> b = new A<>();
        b.setItem(1234);
        System.out.println(b.getItem());
    }

}

하나의 클래스에서 다른 타입의 객체들이 인스턴스화 되었다.

생략 가능 유뮤

  1. 클래스명과 생성자 명이 동일한 경우 생성자쪽 제네릭타입 작성 생략가능
  2. 제네릭 타입을 지정해주지 않는다면, 제네릭 타입으로 올수있는 것중 최대 클래스가 온다.

제네릭 사용 이유 다시 복습

클래스나 메서드의 코드를 작성할 때, 타입을 구체적으로 지정하는 것이 아니라, 추후에 지정할 수 있도록 일반화해두는 것을 의미합니다. 즉, 작성한 클래스 또는 메서드의 코드가 특정 데이터 타입에 얽매이지 않게 해둔 것을 의미

제한된 제네릭 클래스

타입 매개변수를 선언할 때 extends를 작성해주면 확장한 클래스의 하위 클래스만 지정하도록 제한시킴

 class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }

class Basket<T extends Flower> {
   private T item;
	
		...
}
public static void main(String[] args) {

		// 인스턴스화 
		Basket<Rose> roseBasket = new Basket<>();
		Basket<RosePasta> rosePastaBasket = new Basket<>(); // 에러
}

특정 인터페이스를 구현하면서 동시에 인터페이스를 구현한 특정클래스만 타입으로 지정가능

interface plant {
}

class Flower implements plant {
};

class Rose extends Flower {

}

class RosePasta {
}

class Basket<T extends Flower & plant> {
  private T item;
}

public class Main {
  public static void main(String[] args) {
      Basket<Flower> flowerBasket = new Basket<>(); // 타입이 Flower이면서 plant를 구현했기 때문에 사용가능
      Basket<Rose> roseBasket = new Basket<>(); //Flower를 상속받고 Flower가 plant를 구현했기 때문에 사용가능
      Basket<RosePasta> rosePastaBasket = new Basket<RosePasta>(); //둘다 아니라서 사용불가 
  }
}

중요한점은 interface는 구현이기 때문에 implements를 사용하지만 제네릭에서는 구분없이 extends를 사용한다.

static 제네릭 메서드

public static <T>(매개변수 타입) String(리턴타입) method1(T t) {} 

이런식으로 사용한다. 만약 제네릭 클래스 내부에 제네릭 static메소드가 있다면,

class A <T t>{
private T name;
 
public static <T t> T method1(T t){
return t;
}

위의 static메소드는 사용하는데 문제가 있다. static메소드는 객체를 생성하지 않고 사용하는 메소드인데 지금 리턴타입이 A클래스의 타입으로 지정되어있다. 따라서 A클래스의 타입을 지정하려면 객체를 생성해야하는데 이렇게되면 static메서드를 사용하는 의미가 사라진다. 따라서 아래와 같이

class A <T t>{
private T name;
 
public static <T t> int method1(T t){
return t;
}

이렇게 리턴타입을 명확히 지정해주어야지 static제네릭 메서드를 사용할수있다.

여기서 중요한점은 static메서드에 있는 T와 A클래스에 있는 T가 다른 T라는 점을 알아두어야한다. 일반 제네릭메서드 또한 저 자리에 들어가는 T는 메소드의 매개변수타입을 정해주는 데이터 타입 T이다.

wrapper class

profile
많은 도움 얻어가시길 바랍니다!

0개의 댓글