안녕하세요 알통몬입니다. 공감 및 댓글은 포스팅 하는데 아주아주 큰 힘이 됩니다!! 포스팅 내용이 찾아주신 분들께 도움이 되길 바라며 더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^ |
지난 포스팅에 이어 제네릭에 대해 공부하겠습니다.
지난 포스팅이 궁금하시다면 아래 링크를 클릭하시면 됩니다~
2017/03/18 - [자바] - Java generic 자바 제네릭 - 제네릭 타입 class 와 interface / 멀티타입 파라미터 class, interface / 메소드 R method( T t)
타입 파라미터에 지정되는 구체적인 타입을 종종 제한할 필요가 있는데요.
예를 들어서 숫자를 연산하는 제네릭 메소드는 매개값으로 Number 타입이나
하위 클래스 타입의 인스턴스(Byte, Short, Integer, Long, Double)만 가져야해요.
이것이 제한된 타입 파라미터가 필요한 이유입니다.
선언방법은 타입 파라미턴 뒤에 extends 키워드를 붙이고 상위 타입을 명시하면 됩니다.
상위 타입은 인터페이스도 가능하며 인터페이스도 implements가 아닌 extends를 사용합니다.
public <T extends 상위타입> 리턴타입 메소드(매개변수,...) { ...... }
타입 파라미터에 지정되는 구체적인 타입은
상위 타입 or 상위 타입의 하위 또는 구현 클래스만 가능.
* 메소드의 중괄호{ } 안에서 타입 파라미터 변수로
사용가능한 것은 상위 타입의 멤버(필드 또는 메소드) 로 제한.
예제)
제네릭 메소드 >>
public class Util {
public static <T extends Number> int compare( T t1, T t2) {
double val1 = t1.doubleValue();
double val2 = t2.doubleValue();
return Double.compare(val1, val2);
}
}
실행 클래스 >>
public class BoundedTypeParameterExample {
public static void main(String[] args) {
int result1 = Util.compare(3,5);
int result2 = Util.compare(4,3, 3);
실행은 각자해보시길 ㅎㅎ
다음은 와일드 카드 타입에 대해 공부하겠습니다.
일반적으로 코드에서 ?는 와일드 카드라고 하는데요.
제네릭 타입을 매개값이나 리턴 타입으로 사용할 때
와일드 카드를 사용할 수 있어요.
제네릭타입<?> : 제한 없음
>> 타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스, 인터페이스 타입이 올 수 있음.
제네릭타입<? extends 상위타입> : 상위 클래스 제한
>> 타입 파라미터를 대치하는 구체적 타입으로 상위타입이나 하위 타입만 올 수 있음.
제네릭타입<? super 하위 타입> : 하위 클래스 제한
>> 타입 파라미터를 대치하는 구체적 타입으로 하위 타입이나, 상위 타입만 올 수 있음.
예제)
public class Course<T> {
private String name;
private T[] students;
public Course(String name, int capacity) {
this.name = name;
students = ( T[] )( new Object[capacity]);
// 타입 파라미터로 배열을 생성하려면 new T[n]으로 생성할 수 없습니다.
위 코드처럼 생성해야 합니다.
}
public String getName() {
return this.name;
]
public T[] getStudents() {
return this.student;
}
public void add(T t) {
for(int i = 0; i<students.length; i++) {
if(students[i] == null ) {
students[i] = t;
break;
}
}
}
}
수강생이 될 수 있는 타입의 4가지 클래스
Person 클래스
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() { return name; }
public String toString() { return name; }
}
Worker 클래스
public class Worker extends Person {
public Worker(String name) {
super(name);
}
}
Student 클래스
public class Student extends Person {
public Student(String name) {
super(name);
}
}
HighStudent 클래스
public class HighStudent extends Student {
public HighStudent(String name) {
super(name);
}
}
*Course<?>
: 수강생은 모든 타입이 될 수 있다.
*Course<? extends Student>
: 수강생은 Student와 highStudent만 될 수 있다.
*Course<? super Worker>
: 수강생은 Worker 과 Person만 될 수 있다.
예제)
import java.util.Arrays;
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) {
System.out.println(course.getName() + " 수강생: " +
Arrays.toString(course.getStudents()) );
}
public static void registerCourseWorker(Course<? super Worker> course) {
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> highStudentCourse =
new Course<HighStudent>("고등학생과정", 5);
highStudentCourse.add(new HighStudent("고등학생"));
registerCourse(personCourse);
registerCourse(workerCourse);
registerCourse(studentCourse);
registerCourse(highStudentCourse);
System.out.println();
//registerCourseStudent(personCourse); (x)
//registerCourseStudent(workerCourse); (x)
registerCourseStudent(studentCourse);
registerCourseStudent(highStudentCourse);
System.out.println();
registerCourseWorker(personCourse);
registerCourseWorker(workerCourse);
//registerCourseWorker(studentCourse); (x)
//registerCourseWorker(highStudentCourse); (x)
}
}
마지막으로 제네릭 타입과 상속입니다.
제네릭 타입도 부모 클래스가 될 수 있는데요.
또한 자식 제네릭은 타입을 추가적으로 가질 수도 있습니다.
ex)
public class Child<T,M> extends Parent<T,M> { ... }
public class Child<T, M, C> extends Parent<T, M> { ... }
바로 예제를 보겠습니다.
public class Parent<T, M> {
private T kind;
pirvate M model;
public T getKind() {
return this.kind;
}
public M getModel() {
return this.model;
}
public void setKind(T kind) {
this.kind = kind;
}
public void setModel(M model) {
this.model = model;
}
}
class Tv { }
public Child<T, M, C> extend Parent<T, M> {
private C company;
public C getCompany() {
return this.company;
}
public void setCompany(C company) {
this.company = company;
}
}
또한 제네릭 인터페이스를 구현한 클래스도 제네릭 타입이 됨.
public interface Storage<T> {
public void add(T item, int index);
public T get(in 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) {
array[index] = item;
}
@Override
public T get(int index) {
return array[index];
}
}
마지막으로 실행 예제 클래스
public class ChildAndStorageImpl {
public static void main(String[] args) {
Child<Tv, String, String> child = new Child<>();
child.setKind(new Tv());
chid.setModel("OLED TV");
child.setCompany("LG");
Strorage<Tv> storage = new StorageImpl<Tv>(1000);
storage.add(new Tv(), 0);
Tv tv = storage.get();
}
}
여기까지 제네릭이었습니다.
감사합니다.