Ⅰ. 제네릭
1. 제네릭
- 미리 정해둘 수 없는 참조 타입을 비워두는 기법
→ 즉, 어디에 어떤 타입이 쓰일지 모를 때, 그 타입의 자리를 비워둠
- 제네릭을 이용하면 타입이 정해지지 않은 클래스와 인터페이스를 만들 수 있음
2. 제네릭 선언 방법
- < > 기호를 사용 (< > 안에 T를 기입)
※ T : 타입 매개변수 (비워두고 싶은 부분 표시)
※ 매개변수화 타입 : 제네릭에 인자를 넣어서 완성된 타입
3. 타입 매개변수의 일반적인 이름 규칙
- 대문자로 알파벳 하나만 쓰기
4. 제네릭 관련 예제1
// Example1 (제네릭이 필요한 이유)
package sample;
class Apple {
// toString() : 오브젝트클래스로부터 상속되는 오버라이딩 메소드
// :객체를 선언하고 그 객체 이름을 print 하였을때,
// 객체의 시스템 주소 값이 아닌 의미 있는 값으로 재설정 시키는 역할을 수행
public String toString() {
return "I am an apple";
}
}
class Banana {
public String toString() {
return "I am a banana";
}
}
class Box {
private Object fruit; // 위 2개의 클래스는 Object의 자녀 클래스 (다형성을 활용)
public void set(Object f) {
this.fruit = f;
}
public Object get() {
return this.fruit;
}
}
public class Main {
public static void main(String[] args) {
Box appleBox = new Box();
Box bananaBox = new Box();
// 현재 상태는, 실수를 유발하기 쉬운 상태
appleBox.set(new Apple());
bananaBox.set("바나나"); // 다형성으로 인한 실수 유발
Apple a = (Apple)appleBox.get(); // Object를 다운캐스팅
Banana b = (Banana)bananaBox.get(); // 문제를 파악하기조타 쉽지 않음
System.out.println(a);
System.out.println(b);
}
}
// 다형성을 활용하는 것은 좋으나, 어떤 자료를 받을지 명시가 되어 있지 않아 주의하지 않으면 실수 발생
// Example2
package sample;
class Apple {
public String toString() {
return "I am an apple";
}
}
class Banana {
public String toString() {
return "I am a banana";
}
}
// 제네릭
class Bucket<T> {
private T fruit;
public void set(T f) {
this.fruit = f;
}
public T get() {
return this.fruit;
}
}
public class Main {
public static void main(String[] args) {
// 제네릭에 인자 넣어서 완성된 타입 : 매개변수화 타입
Bucket<Apple> appleBucket = new Bucket<>();
Bucket<Banana> bananaBucket = new Bucket<>();
appleBucket.set(new Apple());
bananaBucket.set(new Banana());
Apple a = appleBucket.get();
Banana b = bananaBucket.get();
System.out.println(a);
System.out.println(b);
}
}
5. 다중 매개변수 기반 제네릭 크래스
// Example3
package sample;
// 서랍의 위아래 칸에 객체 넣기 예제
// 서랍의 Top & Bottom
class Drawer<T, B> {
private T top;
private B bottom;
public void set(T t, B b) {
this.top = t;
this.bottom = b;
}
public String toString() {
return this.top + " & " + this.bottom;
}
}
public class Main {
public static void main(String[] args) {
// <> 안에 int가 아닌 Integer 즉, 참조자료형으로 써야 함
Drawer <String, Integer> d = new Drawer<>();
d.set("pencil", 10);
System.out.println(d);
}
}
6. 제네릭의 특징
- 타입 인자를 받아서 사용 (단, 참조 자료형이어야 함)
- 자바에서는 기본 자료형의 객체화 타입인 '래퍼 클래스' 라는 것을 지원
※ 래퍼 클래스 : 기본 자료형 값을 보유한 포장지를 만드는 클래스
- 모든 기본 자료형은 대응하는 래퍼 클래스가 존재
- 박싱 : 기본 자료형 값을 래퍼 클래스로 초기화 하는 작업
- 언박싱 : 래퍼 클래스는 기본 자료형 값을 다시 내보낼 수 있음
※ 래퍼 클래스는 좋지만 기본 자료형보다 훨씬 큰 메모리 크기를 사용해야 하므로 권장하지 않음
// Example
package sample;
public class Main {
public static void main(String[] args) {
int a = 33; // 일반 변수. 이는 곧 값이며, 객체가 아님
// 래퍼 클래스는 객체를 생성
// 박싱 작업 실행
Integer num1 = new Integer(33); // 33과 같은 취급을 받는 객체
Double num2 = new Double(3.14); // 3.14와 같은 취급을 받는 객체
Integer num3 = 50; // 래퍼클래스는 그냥 값만 써도 '오토 박싱'을 함
// 래퍼클래스는 기본자료형 값을 다시 내보낼 수 있음 (언박싱)
int b = num3.intValue();
}
}
- 매개변수화 타입도 타입임 → 따라서 타입 인자가 될 수 있음
// Example
package sample;
// 매개변수화 타입도 타입임 → 따라서 타입 인자가 될 수 있음
class Container<T> {
private T data;
public void set(T d) {
this.data = d;
}
public T get() {
return this.data;
}
}
public class Main {
public static void main(String[] args) {
Container<String> a = new Container<>();
a.set("자바 열공!");
// 매개변수화 타입으로 생성한 객체를 제네릭으로 변수화 할 수 있음
Container<Container<String>> b = new Container<>();
b.set(a);
Container<Container<Container<String>>> c = new Container<>();
c.set(b);
System.out.println(c.get().get().get()); // 3번 중첩을 하였으므로 3번 get을 해야 함
}
}
7. 제네릭 관련 예제2
// Example1
package sample;
// 아래 코드가 실행되도록 클래스 Basic을 정의해보자
class Basic<T> {
private T data;
public void setData(T d) {
this.data = d;
}
public void showYourData() {
System.out.println(this.data);
}
}
public class Main {
public static void main(String[] args) {
Basic<String> base1 = new Basic<>();
Basic<Integer> base2 = new Basic<>();
Basic<Double> base3 = new Basic<>();
base1.setData("하하");
base2.setData(10);
base3.setData(10.11);
// 콘솔 출력 println();
base1.showYourData(); // 하하
base2.showYourData(); // 10
base3.showYourData(); // 10.11
}
}
// Example2
package sample;
// 아래 코드가 실행 가능하도록 클래스를 정의해보자
class MyArray<T> {
T[] arr;
void setArr(T[] a) {
this.arr = a;
}
void viewArr() {
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
System.out.print(" ");
}
System.out.println("");
}
}
public class Main {
public static void main(String[] args) {
MyArray<Integer> arr1 = new MyArray<>();
MyArray<String> arr2 = new MyArray<>();
Integer[] i_arr = {1, 2, 3 ,4, 5};
arr1.setArr(i_arr);
String[] s_arr = {"hi", "bye"};
arr2.setArr(s_arr);
// println();
arr1.viewArr(); // 1 2 3 4 5
arr2.viewArr(); // hi bye
}
}
'Programming Language > Java' 카테고리의 다른 글
컬렉션 프레임 워크 - 1. 컬렉션 프레임워크 (Collection Framework) (0) | 2022.07.19 |
---|---|
BigInteger Class (0) | 2022.07.18 |
스레드(Thread) - 5. Thread 동기화 (0) | 2022.07.15 |
스레드(Thread) - 4. Thread의 속성 (0) | 2022.07.15 |
스레드(Thread) - 3. Thread의 생성 및 실행방법 (0) | 2022.07.15 |