[이것이 자바다] 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