[이것이 자바다] 13장 정리, 연습문제
자바의 제네릭에 대한 내용을 다룬 포스트입니다. 제네릭의 개념, 사용법, 제한된 타입 파라미터, 와일드카드 타입 파라미터 등에 대해 다루고 있습니다.
Jan 17, 2024
Box.java
package ch13; public class Box<T, K> { private T t; private K k; public T content1; public K content2; }
BoxExam.java
package ch13; public class BoxExam { public static void main(String[] args) { Box<Integer, String> box1 = new Box<>(); Box<String, Boolean> box2 = new Box<>(); box1.content1 = 100; box1.content2 = "1oo"; box2.content1 = "string"; box2.content2 = true; System.out.println(box1.content1 + box1.content2); } }
핵심 키워드
- 제네릭이란 결정되지 않은 타입을 파라미터로 처리하고 실제 사용할 때 파라미터를 구체적인 타입으로 대체시키는 기능이다.
Car.java
package ch13; public class Car { }
Tv.java
package ch13; public class Tv { }
Product.java
package ch13; public class Product<K, M> { private K kind; private M model; public K getKind() { return kind; } public void setKind(K kind) { this.kind = kind; } public M getModel() { return model; } public void setModel(M model) { this.model = model; } }
GenericExam1.java
package ch13; public class GenericExam1 { public static void main(String[] args) { Product<Tv, String> product1 = new Product<>(); product1.setKind(new Tv()); product1.setModel("삼성 TV"); Tv tv = product1.getKind(); System.out.println(product1.getModel()); Product<Car, String> product2 = new Product<>(); product2.setKind(new Car()); product2.setModel("현대 자동차"); Car car = product2.getKind(); System.out.println(product2.getModel()); } }
핵심 키워드
- 제네릭 타입은 결정되지 않은 타입을 파라미터로 가지는 클래스와 인터페이스다.
- 제네릭 타입은 선언부에 <> 부호가 붙고 그 사이에 타입 파라미터들이 위치한다.
- 타입 파라미터는 일반적으로 대문자 알파벳 한 글자로 표현한다.
Rentable.java
package ch13; public interface Rentable<R> { R rent(); }
Home.java
package ch13; public class Home { public void turnOnLight() { System.out.println("전등을 켭니다."); } }
Car.java
package ch13; public class Car { public void run() { System.out.println("자동차가 달립니다."); } }
HomeAgency .java
package ch13; public class HomeAgency implements Rentable<Home>{ @Override public Home rent() { return new Home(); } }
CarAgency.java
package ch13; public class CarAgency implements Rentable<Car>{ @Override public Car rent() { return new Car(); } }
RentExam.java
package ch13; public class RentExam { public static void main(String[] args) { HomeAgency ha = new HomeAgency(); Home home = ha.rent(); home.turnOnLight(); CarAgency ca = new CarAgency(); Car car = ca.rent(); car.run(); } }
핵심 키워드
- 인터페이스를 제네릭 타입으로 선언해서 해당 타입 파라미터를 각각 다른 클래스로 대체해서 구현할 수 있다.
Person.java
package ch13; public class Person { } class Worker extends Person{ } class Student extends Person{ } class HighStudent extends Student{ } class MiddleStudent extends Student{ }
Applicant.java
package ch13; public class Applicant<T> { public T kind; public Applicant(T kind) { this.kind = kind; } }
Course.java
package ch13; public class Course { public static void registerCourse1(Applicant<?> applicant) { System.out.println(applicant.kind.getClass().getSimpleName() + "이(가) Course1을 등록함"); } // 사람이면 다 가능 public static void registerCourse2(Applicant<? extends Student> applicant) { System.out.println(applicant.kind.getClass().getSimpleName() + "이(가) Course2을 등록함"); } // 학생만 가능 public static void registerCourse3(Applicant<? super Worker> applicant) { // Worker를 포함한 부모들만 가능 System.out.println(applicant.kind.getClass().getSimpleName() + "이(가) Course3을 등록함"); } // 근로자를 포함한 클래스만 가능 }
ApplyExam.java
package ch13; public class ApplyExam { public static void main(String[] args) { Course.registerCourse1(new Applicant<Person>(new Person())); Course.registerCourse1(new Applicant<Worker>(new Worker())); Course.registerCourse1(new Applicant<Student>(new Student())); Course.registerCourse1(new Applicant<HighStudent>(new HighStudent())); Course.registerCourse1(new Applicant<MiddleStudent>(new MiddleStudent())); // Course.registerCourse2(new Applicant<Person>(new Person())); // 학생만 가능 // Course.registerCourse2(new Applicant<Worker>(new Worker())); Course.registerCourse2(new Applicant<Student>(new Student())); Course.registerCourse2(new Applicant<HighStudent>(new HighStudent())); Course.registerCourse2(new Applicant<MiddleStudent>(new MiddleStudent())); Course.registerCourse3(new Applicant<Person>(new Person())); Course.registerCourse3(new Applicant<Worker>(new Worker())); // Course.registerCourse3(new Applicant<Student>(new Student())); // 근로자와 그 부모만 가능 // Course.registerCourse3(new Applicant<HighStudent>(new HighStudent())); // Course.registerCourse3(new Applicant<MiddleStudent>(new MiddleStudent())); } }
핵심 키워드
- 제네틱 타입을 매개값이나 리턴 타입으로 사용할 때 타입 파라미터로 ?(와일드카드)를 사용할 수 있다.
- 와일드카드는 범위에 있는 모든 타입으로 대체할 수 있다는 표시이다.
- 리턴타입 메소드명(제네릭타입<? extends 클래스명> 변수) { … } 이라는 선언이 있을 때 해당 메소드는 상속받은 클래스의 자식 클래스만 사용 가능하다.
- 반대로 리턴타입 메소드명(제네릭타입<? super 클래스명> 변수) { … } 이라는 선언이 있을 때 해당 메소드는 해당 클래스를 포함한 부모만 사용이 가능하다.
연습문제 2번.java
package ch13.example; public class Container2<T> { private T t; public T get() { return t; } public void set(T t) { this.t = t; } }
연습문제 3번.java
package ch13.example; public class Container3<T, K> { private T t; private K k; public T getKey() { return t; } public K getValue() { return k; } public void set(T t, K k) { this.t = t; this.k = k; } }
연습문제 4번.java
package ch13.example; public class Util { public static <K,V> V getValue(Pair<K,V> p, K k) { // <타입 파라미터 정의> 리턴타입 메소드명(매개변수) if(p.getKey()==(k)) { return p.getValue(); }else { return null; } } }
결론
해당 문제를 풀면서 자바에서 제네릭이 가지는 의미, 타입, 메소드, 제한된 타입 파라미터, 와일드카드 타입 파라미터를 다루는 방법을 익힐 수 있었다.
Share article