티스토리 뷰
Generic의 <> 안에는 여러 개의 타입을 써넣을 수 있지만, 그 타입은 반드시 참조형이어야 한다! (기본형 불가)
ex)
class Person<T, E> {
T name;
E age;
Person(T name, E age) {
this.name = name;
this.age = age;
}
}
public class GenericEx {
public static void main(String[] args) {
Person<String, int> p1 = new Person<String, int>("체봄", 22); // 오류 발생!!
System.out.println("name: "+p1.name+", age: "+p1.age);
}
}
위와 같이 코드를 작성하면 오류가 발생한다.
그 이유는 Generic의 <> 안에는 참조형만 쓸 수 있는데 기본형인 int 를 썼기 때문이다.
age는 정수형 숫자를 담아야 하는데 Generic에는 int형을 쓸 수가 없다. 이러한 경우에 Wrapper 클래스가 필요한 것이다!
따라서, 코드를 다음과 같이 수정하여야 한다.
class Person<T, E> {
T name;
E age;
Person(T name, E age) {
this.name = name;
this.age = age;
}
}
public class GenericEx {
public static void main(String[] args) {
Person<String, Integer> p1 = new Person<String, Integer>("체봄", new Integer(22)); // 오류 해결
System.out.println("name: "+p1.name+", age: "+p1.age);
}
}
실행 결과>
name: 체봄, age: 22
Generic의 생략
위 코드의 Person<String, Integer> p1 = new Person<String, Integer>("체봄", new Integer(22)); 부분에서,
Person 클래스의 생성자 매개변수를 통해서 Generic의 <> 안에 어떤 타입이 들어갈 것인지 알 수 있으므로 <>는 생략할 수 있다.
따라서, Person p1 = new Person("체봄", new Integer(22)); 과 같이 생략하여 쓸 수 있다.
심화>
package GenericEx;
class Data {
public String name;
Data(String name) {
this.name = name;
}
}
class Person<T, E> {
public T data;
public E age;
Person(T data, E age) {
this.data = data;
this.age = age;
}
}
public class GenericEx2 {
public static void main(String[] args) {
Person p1 = new Person(new Data("체봄"), new Integer(22));
System.out.println("name: " + p1.data.name + ", age: " + p1.age); // 오류 발생!!!
}
}
위와 같이 Generic에서 <> 를 모두 생략하여 객체 p1을 생성하였을 때, 'p1.data.name' 부분 에서 오류가 발생한다.
그 이유는 <>를 생략하였으므로 p1.data의 타입이 명시되지 않아 Data 클래스의 내부 변수인 name에 접근할 수 없기 때문이다.
해결방법 1)
Person<Data, Integer> p1 = new Person(new Data("체봄"), new Integer(22)); 와 같이 써서 타입을 명시해준다.
해결방법 2)
p1.data.name을 p1.data로 바꾸면 p1.data는 Data형 객체이므로 객체의 toString 함수가 호출된다.
따라서, Data 클래스 내부에 toString 함수를 다음과 같이 오버라이딩한다.
public String toString() {
return name;
}
메소드에서의 Generic 사용
※ 사용법
: 접근제어자 <T> 반환형 메소드명(T 변수명) { }
-> 메소드의 매개변수에 Generic 타입을 사용하기 위함!
ex)
class Person<T> {
// 메소드에서의 Generic 사용
public <T> void getName(T name) {
System.out.println("제 이름은 " + name + " 입니다.");
}
}
public class GenericEx {
public static void main(String[] args) {
Person<String> p1 = new Person<String>();
p1.<String> getName("체봄"); // p1.getName("체봄");으로 써도 됨
}
}
'p1.<String> getName("체봄");' 부분에서 메소드의 매개변수를 통해 타입을 알 수 있으므로 <>를 생략하여 p1.getName("체봄");과 같이 작성하여도 된다.
Generic의 제한
Generic 사용 시 타입이 정해져 있지 않기 때문에 목적에 맞지 않는 잘못된 타입이 올 수도 있다.
이러한 경우를 막기 위해, Generic이 목적에 부합하는 클래스(또는 인터페이스)를 상속받도록 함으로써 Generic을 제한할 수 있다.
ex)
package GenericEx;
class StudentData {
String name;
int age;
StudentData(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
class Person <T> {
public T data;
Person(T data) {
this.data = data;
}
}
public class GenericEx {
public static void main(String[] args) {
Person p1 = new Person("체리");
}
}
Person 클래스에 StudentData를 Generic으로 사용하여 학생의 데이터를 얻으려는 것을 예측할 수 있다.
그런데 main 메소드에서 Person 클래스에 StudentData 객체가 아닌 String 문자열을 인자로 넘겨주었다.
이 경우 본래 코드의 목적과 어긋나므로 잘못된 코드가 된다. 이러한 경우를 막기 위해 Generic의 제한이 필요한 것이다!
수정한 코드는 다음과 같다.
package GenericEx;
interface Data {
String getName();
int getAge();
}
class StudentData implements Data{
String name;
int age;
StudentData(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
class Person <T extends Data> {
public T data;
Person(T data) {
this.data = data;
}
public void printInfo(T data) {
System.out.println("이름: "+data.getName()+", 나이: "+data.getAge());
}
}
public class GenericEx {
public static void main(String[] args) {
StudentData sd = new StudentData("체봄", 22);
Person p1 = new Person(sd);
p1.printInfo(sd);
}
}
우선 Person 클래스의 Generic이 Data라는 인터페이스를 상속받게 함으로써, Data를 상속받지 않은 타입이 Generic에 들어오지 못하게 제한을 해주었다. (여기서 Generic의 타입으로는 Data와 Data를 상속받은 클래스만이 가능)
그러므로 이전의 경우처럼 Person 객체 생성 시 String 타입을 인자로 넣어주는 실수를 완전히 막을 수 있다.
Data 인터페이스를 implement한 StudentData 클래스 객체를 만들어 Person 객체의 인자에 전달해준다.
※ Generic 타입의 배열을 T arr[] = new T[5]; 와 같은 형식으로 생성할 수 없다 !
'Java, JavaScript' 카테고리의 다른 글
[Java] Collections Framework - Map (0) | 2019.06.18 |
---|---|
[Java] Collections Framework - Collection(List, Set) (0) | 2019.06.18 |
[Java] enum 클래스 (0) | 2019.06.14 |
[Java] Wrapper 클래스 (0) | 2019.06.14 |
[Java] Object 클래스의 기본 메소드 (0) | 2019.06.14 |