제네릭스(Generics)

규칙
컴파일시 타입을 체크해 주는 기능(compile-time type check) - JDK1.5
객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여줌.
   ㄴ( 제네릭으로 특정타입만 들어올수 있도록 선언하기에, 다른타입이 들어오면 컴파일에러 확인가능)
객체를 생성시, 타입변수(E) 대신  →  실제 타입(Tv)을 지정(대입)  ex. ArrayList<Tv> tvList = new ArrayList<Tv>();
참조변수와 생성자의 대입된 타입은 일치해야한다.
제네릭 클래스간의 다형성은 성립한다.(여전히 대입된 타입은 일치해야한다.)
매개변수의 다형성도 성립한다.

※ 예시
클래스 안에 Object 타입이 있는 것들은 <제네릭>을 붙여주는걸로 바뀜 ( JDK1.5 버전 이후)
ArrayList (일반클래스)  →  ArrayList<타입 or Object> 

실행중에 에러 발생을 방지를 위한 작업
에러 발생시 실행중 에러보다는,    컴파일시 에러발생으로 유도. 
왜? 중간에 실행하다가 멈추면 작업하던게 모두 날라가니까.
String str  = null;                                          →                                  String str = "";   
    (안좋은예)                                                                                         ( 추천 )

ex) str.length()를 안좋은예로 하게되면 null로 초기화시 NullPointerException 발생.
                               추천예로 진행시 0 반환.


Object[] Arr = null                                →                         Object Arr = new Object[0];   or   Object Arr = {};
    (안좋은예)                                                                                                         ( 추천 )

ex) arr.length()를 안좋은예로 하게되면 null로 초기화시 NullPointerException 발생
                                 추천예로 진행시 0 반환.


ClassCastExcetion을 막기위해 <제네릭> 사용.

 


타입 변수

규칙
클래스를 작성할 때, Object타입 대신 →  타입 변수(E)를 선언해서 사용.

 


제네릭 용어

 


제네릭 타입과 다형성

예시

public class ex6 {
	public static void main(String[] args) {

		ArrayList<Product> ProductList = new ArrayList<Product>();
		ArrayList<Tv> 			tvList = new ArrayList<Tv>();
		List<Tv>				tvList2 = new ArrayList<Tv>();//원시타입 다형성가능
		
		ProductList.add(new Tv());
		ProductList.add(new Audio());
		
		tvList.add(new Tv());
		tvList.add(new Tv());
		
		printAll(ProductList);
		printAll2(tvList);
		
	}
	public static void printAll(ArrayList<Product> proList) {
		for(Product p : proList) {
			System.out.println("Product 타입 : " + p);
		}
	}
	public static void printAll2(ArrayList<Tv> tvList) {
		for(Product p : tvList) {
			System.out.println("Tv 타입 : " + p);
		}
	}
}


Iterator<E>

규칙
클래스를 작성할 때, Object타입 대신 T와 같은 타입 변수를 사용

class Student9{
	String name = "";
	int ban;
	int no;
	public Student9(String name, int ban, int no) {
		super();
		this.name = name;
		this.ban = ban;
		this.no = no;
	}
}
public class ex6 {
	public static void main(String[] args) {
		
		ArrayList<Student9> list = new ArrayList<Student9>();
		list.add(new Student9("자바왕", 1, 1));
		list.add(new Student9("자바도사", 1, 2));
		list.add(new Student9("홍길동", 2, 1));
		
		
		Iterator<Student9> it = list.iterator();
		
		while(it.hasNext()) {
			Student9 s = it.next();
			System.out.println(s.name + "    " + s.ban + "반 "+ s.no+ "번");
		}
	}
}

 

 


HashMap<K,V>

여러 개의 타입변수가 필요한 경우, 콤마(,)를 구분자로 선언

class Student9{
	String name = "";
	int ban;
	int no;
	int kor;
	int eng;
	int math;
	
	public Student9(String name, int ban, int no, int kor, int eng, int math) {
		super();
		this.name = name;
		this.ban = ban;
		this.no = no;
		this.kor = kor;
		this.eng = eng;
		this.math = math;
	}
}
public class ex6 {
	public static void main(String[] args) {
		
		HashMap<String,Student9> map = new HashMap<String,Student9>();
		
		map.put("자바왕", new Student9("자바왕", 1, 1, 100, 100, 100));
		
		Student9 s = map.get("자바왕");
		System.out.println(s);
		System.out.println(map);
	}
}


제한된 제네릭 클래스

규칙
extends로 대입 할 수 있는 타입을 제한

interface Eatable{}

class Fruit implements Eatable{
	public String toString() { return "Fruit"; }
}

class Apple extends Fruit	{	public String toString() { return "Apple";	}}
class Grape extends Fruit	{	public String toString() { return "Grape";	}}
class Toy					{	public String toString() { return "Toy";	}}

class ex6 {
	public void main(String[] args) {
		
		FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
		FruitBox<Apple> appleBox = new FruitBox<Apple>();
		FruitBox<Grape> grapeBox = new FruitBox<Grape>();
//		FruitBox<Grape> grapeBox = new FruitBox<Apple>(); 	// 에러. 타입불일치
//		FruitBox<Toy>   toyBox   = new FruitBox<Toy>();		// 에러. 원시타입(FruitBox)에  Toy가 없음

		fruitBox.add(new Fruit());
		fruitBox.add(new Apple());
		fruitBox.add(new Grape());
		appleBox.add(new Apple());
//		appleBox.add(new Grape());  //에러. 형제간이기 때문에 
		grapeBox.add(new Grape());

		System.out.println("fruitBox-"+fruitBox);
		System.out.println("appleBox-"+appleBox);
		System.out.println("grapeBox-"+grapeBox);
	}
}
// 타입변수<> 에서 인터페이스는 & 기호사용 
class FruitBox<T extends Fruit & Eatable> extends Box<T>{}

class Box<T> {
	ArrayList<T> list = new ArrayList<T>();
	void add(T item) { list.add(item);     }
	T get(int i)     { return list.get(i); }
	int size()       { return list.size(); }
	public String toString() { return list.toString();	}
}


제네릭의 제약

 

규칙
타입변수에 대입은 인스턴스 별로 다르게 가능.
static멤버에 타입변수 사용(불가)  왜? static멤버는 모든 인스턴스의 공통이니까
배열 생성할 때 타입변수 사용불가. 타입 변수로 배열 선언은 가능.

 


출처 : 남궁성의 정석코딩

https://www.youtube.com/@MasterNKS

+ Recent posts