20210706 TIL

김진태·2021년 7월 6일
0

TIL

목록 보기
21/28

Generics란?

  • 컴파일시 타입을 체크 해주는 기능 (compile-time type check) -jdk1.5

  • 제네릭스 이전

    public static void main(String[] args) {
    		//컬렉션에는 여러가지 자료형을 담을 수 있다. (list,Set,Map)
    		ArrayList list = new ArrayList();
    		list.add(new String("12345"));
    		list.add(new Book());
    		list.add(new Student());
    		list.add(new Car());
    		
    		System.out.println("저장된 객체 수 : " +list.size());
    		System.out.println("list : "+ list);
    		
    		//책만 꺼내고 싶어요
    		for (int i = 0; i < list.size(); i++) {
    			Object obj = list.get(i);
    			if(obj instanceof Book) {
    				System.out.println("책 객체 : " + obj);
    			}
    		}
    		for (int i = 0; i < list.size(); i++) {
    			Object obj = list.get(i);
    			if(obj instanceof Book) {
    			System.out.println("책 객체 : " +obj);	
    			}else if(obj instanceof Car) {
    				System.out.println("자동차 객체 : " + obj);
    			}else if (obj instanceof Student) {
    				System.out.println("학생 객체 : " + obj);
    			}else if (obj instanceof String) {
    				System.out.println("일반 문자 : "+ obj);
    			}
    		}
    		
    	}
    }
    	class Book   {
    		private String bNo;
    		
    		public Book() {}
    		
    		public Book(String bNo) {
    			this.bNo = bNo;
    		}
    
    		@Override
    		public String toString() {
    			return "나는 " + bNo + "입니다.";
    		}
    	}
    		
    	
    	
    	class Student {
    		private String stuNo;
    		public Student() {}
    		@Override
    		public String toString() {
    			return "나는 학생 입니다.";
    		}
    	
    	}
    	
    	class Car  {
    		
    		private String model;
    		public Car() {}
    		public Car(String mdel) {
    			this.model =model;
    			
    		}
    		@Override
    		public String toString() {
    			return "나는" + model + "입니다1";
    		}
    	}
  • 제네릭스 이후

    public static void main(String[] args) {
    		HashMap<String, Book> hmap = new HashMap<>();
    		inputMap(hmap);
    		outputMap(hmap);
    	}
    	
    	public void method1() {
    	
    		ArrayList list1 = new ArrayList();
    		list1.add(new Book());
    		list1.add(new Car());
    		
    		// Book만 받기 위한 리스트
    		ArrayList<Book> list2 = new ArrayList<>();// 뒤는 생략가능
    		list2.add(new Book());
    //		list2.add( new Car()); <-  에러
    		
    		//Book만 받도록 한정지은 컬렉션 객체
    		for(Book bk : list2) {
    			// list2안에 Book객체만 들어있기 때문에
    			// Book 형태로 굳이 형변환 하지 않고도 사용이 가능하다.
    			System.out.println(bk);
    		}
    //		for(Car bk : list2) {
    //			// list2안에 Book객체만 들어있기 때문에
    //			// Book 형태로 굳이 형변환 하지 않고도 사용이 가능하다.
    //			System.out.println(bk);
    //		}
    		
    		for(Object obj : list1) {
    			// list안에 어떠한 자료형이 담겨있을 지 모르기 때문에
    			// Object형태로 받은 다음 Book객체로 변환이 가능한지
    			// 확인이 필요하다 (instanceof 연산자가 필요)
    			if (obj instanceof Book) {
    				Book bk = (Book)obj;
    				System.out.println(bk);
    			}
    		}
    		
    	}
    
    	public static  void inputMap(HashMap<String, Book> hmap) {
    		
    		//전달받은 HashMap에 객체 저장하기
    		hmap.put("1", new Book("갈매기의 꿈"));
    		hmap.put("2", new Book("나의 라임 오렌지나무"));
    		hmap.put("3", new Book("갈매기의 꿈"));
    		hmap.put("4", new Book("자바에서 살아남기"));
    		
    		System.out.println("총 : " +hmap.size() + "권의 책이 저장되었습니다.");
    	}
    	
    	public static void outputMap(HashMap<String, Book> hmap) {
    		// 매개변수로 hashmap을 받아 목록화하여 키의 값을 한개씩 꺼내는 메소드
    		// 1. keySet() 메소드를 사용하는 방법
    		
    		Set<String> keys = hmap.keySet();
    		Iterator<String> iter = keys.iterator();
    		while(iter.hasNext()) {
    			String key = iter.next();
    			System.out.println(key+ " : " + hmap.get(key));
    
    		}
    		
    	}

위의 코드에서 보면 알 수 있듯 제네릭스 이전에는 컬렉션에 자료형을 넣을 때

제한이 없었기 때문에 객체를 꺼내어 사용할 때 incetanceof를 통해 확인 후 사용해야 했다.

하지만 제네릭스의 등장 이후 미리 컬렉션에 저장할 자료형을 한가지로 제한함으로 써

객체를 꺼내어 사용할 떄 객체에 대한 형 변환을 생략해준다!

제네릭스 용어

  • Box - 제네릭 클래스 'T의Box'또는 'T Box'라고 읽는다.
  • T 타입변수 또는 타입 매개변수(T는 타입 문자)
  • Box 원시타입(raw type)

제네릭 타입과 다형성

  • 참조 변수와 생성자의 대입된 타입은 일치해야 한다.
ArrayList<Tv> list = new ArrayList<Tv>();
ArrayList<Product> list = new ArrayList<Tv>();  //에러
  • 제네릭 클래스간 다형성은 성립 (여전히 대입된 타입은 일치)
List<Tv> list = new ArrayList<Tv>(); // 다형성 ArrayList가 List를 구현
List<Tv> list = new LinkedList<Tv>(); // 다형성 LinkedList 가 List를 구현
  • 매개변수의 다형성도 성립
ArrayList<Porduct> list = new ArrayList<Product>();
list.add(new Product());
list.add(new Tv());       // Product의 자손객체 TV
list.add(new Audio());    // Product의 자손객체 Audio

HashMap<K,V>

  • 여러 개의 타입 변수가 필요한 경우, 콤마( , ) 를 구분자로 선언
HashMap<String, Student> map = new HashMap<String, Student>();
map.put("자바왕",new Student("자바킹왕",1,1,100,100,100));

System.out.println(map.get("자바왕").name);

>>> 자바킹왕

제한된 제네릭 클래스

  • extends로 대입할 수 있는 타입을 제한
class Fruit<t extends Fruit>

Fruit 이외의 타입은 들어올 수 없다.

제네릭스의 제약

  • 타입 변수에 대입은 인스턴스 별로 다르게 가능
Box<Apple> appleBox = new Box<Apple>();
Box<Grape> appleBox = new Box<Grape>();
  • static멤버에 타입변수 사용 불가
class Box<T>{
		static T item ; // 에러
		static int compare(T t1, T t2){} // 에러
}
  • 배열 생성할 때 타입변수 사용 불가. 타입 변수로 배열 선언은 가능
class Box<T>{
		T[] itemArr; // 가능
		T[] toArray(){
				T[] tmpArr = new T[itemArr.length]; // 에러 
		}
}

new 연산자로 생성할 때에는 타입이 확정되어있어야 하기 때문에 불가.

T는 어떤타입이 올지 모른다!

와일드카드 <?>

ArrayList<? extends Porduct> list = new ArrayList<Tv>(); // 가능
ArrayList<? extends Porduct> list = new ArrayList<Audio>(); // 가능
ArrayList<Porduct> list = new ArrayList<Tv>(); // 타입 불일치
  • 와일드 카드의 상한 제한. T와 그 `자손`들만 가능
  • 와이들카드의 하한 제한 T와 그 `조상`들만 가능
  • 제한 없음. 모든 타입이 가능 와 동일

제네릭 메서드

  • 제네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
static <T> void sort(List<T> list, Comparator<? super T> c)
  • 클래스의 타입 매개변수와 메서드의 타입 매개변수 는 별개
class FruitBox<T>{ // 다름!!
		static <T> void sort(List<T> list, Comparator<? super T> c){
			...
		}
}
  • 메서드를 호출할 때마다 타입을 대입해야(대부분 생략 가능)
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> fruitBox = new FruitBox<Apple>();

System.out.println(Juicer.<Fruit>makeJuice(fruitBox));
System.out.println(Juicer.<Apple>makeJuice(appleBox));

static <T extends Fruit> Jucice makeJuice(FruitBox<T> box){
			String temp =""
			for (Fruit f :box.getlist()) temp += f+"";
			return new Juice(temp)
}
  • 메서드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가
profile
안녕!

0개의 댓글