Generic

박은빈·2022년 9월 30일
0

자바

목록 보기
5/25
post-custom-banner

Generic이란

직역하면 ‘일반적인’이란 뜻이다. 즉 데이터 형식에 의존하지않고 하나의 값이 여러개의 타입을 가질수 있도록 하는 방법이다

Generic의 장점

  • 잘못된 타입이 들어올 수 있는것을 컴파일 단계에서 방지할 수 있다
  • 클래스 외부에서 타입을 지정해주기때문에 관리하기가 편하다
  • 코드의 재사용성이 높아진다

선언과 사용방법

class CName <T> {
	...
}
Interface IName <T> {
	...
}

CName<데이터 타입> name = new CName<>();

기본적으로 < >를 하고 그 안에 타입을 넣는다.

여기서 T는 암묵적으로 정한 타입명명규칙이다

타입설명
Type
Element
Key
Value
Number

예시

Class CName<E> {
	private E element;
	
	void set(E element) {
		this.element = element;
	}
	
	E get() {
		return element;
	}
}

public class Main { 
		public static void main(String[] args) {
			CName<String> a = new CName<String>();
			CName<Integer> b = new CName<Integer>();
		
			a.set("10");
			b.set(10);

			System.out.println("a data : " + a.get());
			System.out.println("b data : " + b.get());
		}
}

위처럼 타입 지정을 객체선언때 지정해주고 타입을 String, Integer로 다르게 주었다

그리고 결과를 보면 둘다 정상적으로 출력이 된다

여기서 드는 궁금증은 왜 int, char… 가 아닌 Integer인가다

이유는 제네릭에는 참조타입밖에 오지 못한다.

또한 제네릭은 2개를 선언할수있다

Class CName<K,V> {
	private K first;
	private V second
	
	void set(K first, V second) {
		this.first = first;
		this.second = second;
	}
	
	K getF() {
		return first;
	}
	
	V getS() {
		return second;
	}
}

public class Main { 
		public static void main(String[] args) {
			CName<String, Integer> gTest = new CName<String, Integer>();
			
			gTset.set("10",10);

			System.out.println(gTest.getF());
			System.out.println(gTest.getS());
		}
}

위의 코드와 같은 값인 String, Integer로 선언된 10, 10이 나오게 된다

제네릭 메소드

제네릭은 메소드에서도 쓸수가 있다

public <T> T genericMethod(T t) {
	...
}

[접근제어자] <제네릭타입> [리턴타입] [메소드명]([제네릭타입] [파라미터]) {
	...
}

제네릭 메소드는 파라미터의 타입에 따라 T가 결정된다

그리고 제네릭 클래스에서 스태틱(static)은 사용이 불가능하다

이유는 스태틱이 붙을경우 프로그램 실행시 바로 메모리에 올라가는데 제네릭은 타입을 지정해주지 않았기때문에 사용할수가 없다.

class ClassName<E> {
	
	static E genericMethod(E o) {
		return o;
	}
	
}
 
class Main {
 
	public static void main(String[] args) {
 
		// ClassName 객체가 생성되기 전에 접근할 수 있으나 타입을 지정할 방법이 없어 에러남
		ClassName.getnerMethod(3);
 
	}
}

타입을 지정하지 못하기때문에 위의 코드는 에러가 난다

class ClassName<E> {
	 
	private E element; // 제네릭 타입 변수
 
	void set(E element) { // 제네릭 파라미터 메소드
		this.element = element;
	}
 
	E get() { // 제네릭 타입 반환 메소드
		return element;
	}
 
	// 아래 메소드의 E타입은 제네릭 클래스의 E타입과 다른 독립적인 타입이다.
	static <E> E genericMethod1(E o) { // 제네릭 메소드
		return o;
	}
 
	static <T> T genericMethod2(T o) { // 제네릭 메소드
		return o;
	}
 
}
 
public class StaticGeneric1 {
	public static void main(String[] args) {
 
		ClassName<String> a = new ClassName<String>();
		ClassName<Integer> b = new ClassName<Integer>();
 
		a.set("10");
		b.set(10);
 
		System.out.println("a data : " + a.get());
		System.out.println("b data : " + b.get());
		System.out.println();
 
		
		//제네릭 메소드
		System.out.println("<E> returnType : " + ClassName.genericMethod1(3));
		System.out.println("<E> returnType : " + ClassName.genericMethod1("ABCD"));
 
		System.out.println("<T> returnType : " + ClassName.genericMethod1(a));
		System.out.println("<T> returnType : " + ClassName.genericMethod1(3.0));
	}
}

하지만 위의 코드는 가능하다

제네릭 메소드는 제네릭 클래스와 별개로 독립적인 선언이 가능하다

그래서 제네릭클래스의 와 제네릭메소드의는 다른 타입이다

또한 제네릭메소드는 호출시에 타입을 정해주기때문에 스태틱으로 선언이 가능하다

제한된 Generic, 와일드카드(extends, super, ‘?’)

  • extends : extends 뒤에 선언한 타입 밑에 타입들만 선언할 수 있다
  • super : super 뒤에 선언한 타입 위의 타입들만 선언할 수 있따
  • 와일드카드 : <?>로 선언하고 알수없는 타입이다
<K extends T> //T와 T의 하위타입만 가능 (K는 들어오는 타입으로 지정됨)
<K super T> //T와 T의 상위타입만 가능 (K는 들어오는 타입으로 지정됨)

<? extends T> //T와 T의 하위타입만 가능
<? super T> //T와 T의 상위타입만 가능
<?> //모든 타입 가능 <? extends Object>랑 같은 의미

와일드카드

쉽게 말해서 알수없는타입(unknown type)이다

이 ?에는 내가 만든클래스타입, Integer, String 등등 범위가 정말 무제한이다

그래서 extends나 super로 상한선 하한선을 정해주어야한다

profile
안녕하세요
post-custom-banner

0개의 댓글