13.제네릭.

chaean Lee·2021년 2월 11일
0
post-thumbnail

👀이 글은 제가 공부한 것들을 잊어버리지 않기 위해 정리해 놓은 것입니다.

13.1 제네릭을 사용하는 이유는?

제네릭 정의: 클래스, 인터페이스, 메소드를 정의할 때 타입파라미터로 사용할 수 있도록 해준다.

✨컴파일에서 잘못된 타입을 검사해 준다.

✨타입 변환을 제거한다.

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


List<String> list = new ArrayList<String>();     
list.add("hello");
String str = list.get(0);

13.2 제네릭 타입(class< T >,interface< T >)

타입을 파라미터로 가지는 클래스인터페이스를 말한다.

사용이유: ✨타입 변환을 제거한다.

public class Box<T>{
    private T t;                     //T는 Box클래스를 객체로 생성할 때 구체적인 타입으로 변경된다.
	public T get() {return t;}
	public void set(T t) {this.t = t; }
		
}
	


Box<String> box = new Box<String>();

public class Box<String> {              //객체가 생성되면서 타입이 바뀜.
    private String t;
	public String get() {return t;}
	public void set(String t) {this.t = t;}
		
}

13.3 멀티 타입 파라미터(class<k,v,...>,interface<k,v,...>)

제네릭 타입은 두 개 이상의 타입 파라미터를 사용할 수 있다.

public class Product<T, M> {
	private T kind;
	private M model;

	public T getKind() {
		return kind;
	}

	public M getModel() {
		return model;
	}

	public void setKind(T kind) {
		this.kind = kind;
	}

	public void setModel(M model) {
		this.model = model;
	}
}


public static void main(String[] args) {
		
	Product<TV, String> product1 = new Product<TV, String>();
	product1.setKind(new TV());
	product1.setModel("스마트TV");
		
	TV tv = product1.getKind();
	String tvModel = product1.getKind();
		
	Product<Car, String> product1 = new Product<Car, String>();
	product1.setKind(new Car());
	product1.setModel("디젤");
		
	Car tv = product1.getKind();
	String carModel = product1.getKind();

}

13.4 제네릭 메소드(< T, R > R method (T t))

제네릭 메소드는 매개타입리턴타입으로 타입 파라미터를 갖는 메소드를 말한다.

🎈예제1
public < 타입 파라미터 >  리턴타입  메소드면(매개변수,....){.....}
🎈예제2
public class Util {
		
	public static <T> Box<T> boxing(T t){
			
		Box<T> box = new Box<T>();
		box.set(t);
			
		return box;
			
		}
}
 
 
    
public class BoxingMethodExamplw{
	public static void main(String[] args) {
			
		Box<Integer> box1 = Util.<Integer>boxing(100); //🎃제네릭 메소드 호출방법1
		int intvalue = box1.get();
			
		Box<String> box2 = Util.boxing("홍길동");       //🎃제네릭 메소드 호출방법2
		String strvalue = box1.get();
			
	}
}
🎈예제3
public class Pair<K, V> {
	
	private K key;
	private V value;

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

	public K getKey() {
		return key;
	}

	public void setKey(K key) {
		this.key = key;
	}

	public V getValue() {
		return value;
	}

	public void setValue(V value) {
		this.value = value;
	}
	
	

}

public class Util {

	public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
		
		boolean keyCompare = p1.getKey().equals(p2.getKey());
		boolean valCompare = p1.getValue().equals(p2.getValue());

		return keyCompare && valCompare;
	}

}
public class CompareMethodExample {
	
	public static void main(String[] args) {
		
		Pair<Integer , String> p1 = new Pair<Integer, String>(1, "사과");
		Pair<Integer , String> p2 = new Pair<Integer, String>(1, "사과");
		
		boolean result1 = Util.<Integer, String>compare(p1, p2);
		if(result1) {
			System.out.println("논리적으로 동등하다1.");
		}else {
			System.out.println("논리적으로 동등하지 않다1.");
		}
		
		Pair<String , String> p3 = new Pair<String, String>("user1", "사과");
		Pair<String , String> p4 = new Pair<String, String>("user2", "사과");
		
		boolean result2 = Util.compare(p3, p4);
		if(result2) {
			System.out.println("논리적으로 동등하다2.");
		}else {
			System.out.println("논리적으로 동등하지 않다2.");
		}
		
		

	}

}

13.5 제한된 타입 파라미터(< T extends 최상위 타입 >)

타입 파라미터에 구체적인 타입을 제한할 때 사용한다.

상위 타입은 클래스뿐만 아니라 인터페이스도 가능하다.

인터페이스라고 해서 Implements를 사용하지 않는다.

🎈예제1
public class Util {
	
	public static <T extends Number> int compare(T t1, T t2) {
		double v1 = t1.doubleValue();
		double v2 = t2.doubleValue();
		
		return Double.compare(v1, v2);
	}

}

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

		// String str = Util.compare("a", "b"); String은 Number타입이 아님.

		int result = Util.compare(10, 20);
		System.out.println(result);

		int result2 = Util.compare(4.5, 3);
		System.out.println(result2);

	}

}

13.6 와일드카드 타입(< ? >, < ? extends...>, < ? super...>)

제네릭 타입을 매개값이나 리턴 타입으로 사용할 떄 구체적인 타입대신 와일드 카드를 사용할 수 있다.

수강생이 될 수 있는 타입은 4가지 클래스라고 가정하자.

🎈예제1
public class Course<T> {

	private String name;
	private T[] students;

	public Course(String name, int capacity) {
		this.name = name;
		students = (T[]) (new Object[capacity]);
	}

	public String getName() {
		return name;
	}

	public T[] getStudents() {
		return students;
	}

	public void add(T t) {
		for (int i = 0; i < students.length; i++) {
			if (students[i] == null) {
				students[i] = t;
				break;
			}
		}
	}

}


public class WildCardExample {

	public static void registerCourse(Course<?> course) {// 수강생은 모든 타입일 될수 있다.
		System.out.println(course.getName() + "수강생" + Arrays.toString(course.getStudents()));

	}
	public static void registerCourseStudent(Course<? extends Student> course) {// 수강생은 student,highstudent.
		System.out.println(course.getName() + "수강생" + Arrays.toString(course.getStudents()));

	}
	public static void registerCourseWorker(Course<? super Worker> course) {// 수강생은 worker, person 타입일 될수 있다.
		System.out.println(course.getName() + "수강생" + Arrays.toString(course.getStudents()));

	}
	
	public static void main(String[] args) {
		Course<Person> personCourse = new Course<Person>("일반인과정", 5);
		personCourse.add(new Person("일반인"));
		personCourse.add(new Worker("직장인"));
		personCourse.add(new Student("학생"));
		personCourse.add(new HighStudent("고등학생"));
		
		Course<Worker> workerCourse = new Course<Worker>("작장인과정", 5);
		workerCourse.add(new Worker("직장인"));
		
		Course<Student> studentCourse = new Course<Student>("학생과정", 5);
		studentCourse.add(new Student("학생"));
		studentCourse.add(new HighStudent("고등학생"));
		
		Course<HighStudent> highCourse = new Course<HighStudent>("고등학생과정", 5);
		highCourse.add(new HighStudent("고등학생"));
		
		System.out.println("----------------------------------");
		registerCourse(personCourse);//모든 과정 등록 가능
		registerCourse(workerCourse);
		registerCourse(studentCourse);
		registerCourse(highCourse);
		System.out.println();
		
		//registerCourseStudent(personCourse); X
		//registerCourseStudent(workerCourse); X
		registerCourseStudent(studentCourse);  //학생 과정만 등록 가능
		registerCourseStudent(highCourse);
		
		registerCourseWorker(workerCourse);//직장인과 일반인 과정만 등록 가능.
		registerCourseWorker(personCourse);
		
	}

}




13.7 제네릭 타입의 상속과 구현

제네릭 타입도 다른 타입과 마찬가지로 부모 클래스가 될수 있다.

public class ChildProduct<T,M> extends ParentProduct<T,M>{....}
//자식 제네릭 타입은 추가적으로 타입 파라미터를 가질 수 있다.
public class ChildProduct<T,M,C> extends ParentProduct<T,M>{....}
🎈예제1
//부모 제네릭 클래스
public class Product<T, M> {

	private T kind;
	private M model;

	public T getKind() {
		return kind;
	}

	public void setKind(T kind) {
		this.kind = kind;
	}

	public M getModel() {
		return model;
	}

	public void setModel(M model) {
		this.model = model;
	}

}

class Tv {
}

//자식 제네릭 클래스
public class ChildProduct <T,M,C> extends Product<T, M>{
	private C company;

	public C getCompany() {
		return company;
	}

	public void setCompany(C company) {
		this.company = company;
	}
	

}

//제네릭 인터페이스
public interface Storage<T> {
	public void add(T item, int index);

	public T get(int index);
}

//제네릭 구현 클래스
public class StorageImpl<T> implements Storage<T> {
	
	private T[] array;
	
	public StorageImpl(int capacity) {
		this.array = (T[])(new Object[capacity]);
	}

	@Override
	public void add(T item, int index) {
		
	}

	@Override
	public T get(int index) {
		
		return null;
	}

}

//제네릭 타입 사용 클래스
public class ChildProductAndStorageExample {
	
	public static void main(String[] args) {
		ChildProduct<Tv, String, String> product = new ChildProduct<>();
		product.setKind(new Tv());
		product.setModel("SmartTv");
		product.setCompany("samsong");
		
		Storage<Tv> storage = new StorageImpl<Tv>(100);
		storage.add(new Tv(), 0);
		Tv tv = storage.get(0);
		

	}
}
profile
왜! 언제! 어떻게! 😁

0개의 댓글