Generic
✅ Generic 프로그래밍
❓ 로직은 다 똑같은데 datatype만 바꾸는 코드를 짜야 한다면?
❌ object가 최상위클라스니까, object class로 구현해볼까?
그러나 항상 downcasting해야하는 한계가 있다. 😨
- 안전하게 같은 코드를 여러 참조형에 사용하여 코드 재사용성 올리는 프로그램 기법
- 타입을 일반적으로 지정하지 않은 클래스/인터페이스/메소드를 정의
✔️ Convariant
- 상위타입에서 하위타입으로 형 변환 가능
- Number class ➡️ Integer, Double class
✔️ Contravariant
- 하위 타입에서 상위 타입으로 형 변환 가능
Generic type 선언
- class
interface로 선언
- 제네릭 타입은 타입을 parameter로 가지는 클래스와 인터페이스를 말한다.
- class/ interface 이름 뒤에 <> 부호가 붙고 사이에 타입 parameter
- parameter는 꼭 대문자 알파벳 1글자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class GeneralPrint<T> {
private T material;
//이 method를 string, boolean, integer에서도 다 사용하고 싶어(datatype만 다르게 해서 )
public void printMyInfo(){
System.out.println("Using Generic to print " + material + " and this datatype is a "+ material.getClass());
}
//getter, setter
public void setMaterial(T material){
this.material= material;
}
public T getMaterial(){
return this.material;
}
}
public class PrintSituation {
public static void main(String[] args) {
//똑같이 printer이라서 같은 GeneralPrint class 공유하는데, datatype만 다르게 출력하고 싶음
//1️⃣ String printer
//기존에는 이렇게 인스턴스만 만들었다면 여기에 datatype을 붙여준다. <String>
//GeneralPrint printStr= new GeneralPrint();
GeneralPrint<String> printStr= new GeneralPrint<String>();
printStr.setMaterial("So Hee");
// Generic으로 downcast 할 필요 이제 없어짐!
//String materialString= (String) printStr.getMaterial();
//getter해서 method 실행
String materialString= printStr.getMaterial();
printStr.printMyInfo();
//Using Generic to print So Hee and this datatype is a class java.lang.String
//2️⃣ Integer printer
GeneralPrint<Integer> printInt= new GeneralPrint<Integer>();
printInt.setMaterial(123);
int materialInt= printInt.getMaterial();
printInt.printMyInfo();
//Using Generic to print 123 and this datatype is a class java.lang.Integer
//3️⃣ boolean printer
GeneralPrint<Boolean> printBool= new GeneralPrint<Boolean>();
printBool.setMaterial(true);
Boolean materialBool= printBool.getMaterial();
printBool.printMyInfo();
//Using Generic to print true and this datatype is a class java.lang.Boolean
}
}
✅ Generic 심화
✔️ static은 Generic불가
static은 시점: class load 시점
generic 시점: 인스턴스 생성 시점
따라서 generic생성 시점보다 static 시점이 먼저이기 때문에 static은 Generic불가
✔️ Generic은 두 개 이상 사용 가능
✅ Super, Extends
Generic programming 자료형 제한하기
자바 타입 파라미터를 제한하기 위해 사용
- 근데…Generic은 너무 넓은 범위의 datatype 받는거 아니야?
- 내가 원하지 않는 datatype이 Generic에 입력되면 어떡하지? 나는 int만 받고 싶은데
- string들어오면?
💡 Super
- 특정 상위 타입만을 허용
💡 Extends
- 특정 하위 타입만을 허용
- number의 하위 타입인 integer, double만 허용
extends Number
을 사용해 숫자만 Generic에 들어올 수 있도록 한다.- ⭐️ number: float, integer, double 모두 속하는게 number
💡 ?
- 와일드카드
<?>
: 전체 타입 가능<? extends 상위타입 A>
: 상한선, A자식클래스 까지만 가능<? extends 하위타입 B>
: 하한선, B조상클래스까지만 가능
좌표의 거리를 구하기: 우선 extends안 쓰고 구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class Point <T, V>{ //Generic은 두 개 이상 사용 가능
//generic
private T x;
private V y;
//getter
public T getX() {
return x;
}
public V getY() {
return y;
}
//constructor
public Point(T x, V y) {
this.x = x;
this.y = y;
}
//method
public Double caculateDistance(){
//instanceof
//x, y 모두 number의 타입이어야 한다. float, integer, double 모두 number에 속한다.
//x, y 가 숫자가 아니면 null
// 🥱 근데 매번 이렇게 number 아닌 경우 코드로 짜야 함? ➡️ extends number
if(!(this.x instanceof Number)){
return null;
}
if(!(this.y instanceof Number)){
return null;
}
//downcast
Double num1= ((Number) this.x).doubleValue();
Double num2= ((Number) this.y).doubleValue();
return Math.sqrt((Math.pow(num1, 2)) + (Math.pow(num2, 2)));
}
}
public class PointSituation {
public static void main(String[] args) {
Point<Integer, Integer> point1= new Point(1, 5);
Point<Integer, Double> point2= new Point(10, 15.5);
Point<Double, Double> point3= new Point(4.5, 25.75);
//이상한 datatype 넣으면?
Point<String, Double> pointWrong= new Point("Hello", 25.75);
System.out.println(point1.caculateDistance()); //5.0990195135927845
System.out.println(point2.caculateDistance()); //18.445866745696716
System.out.println(point3.caculateDistance()); //26.140246747113924
System.out.println(pointWrong.caculateDistance()); //null
}
}
extends 써서 구현
if문 사용할 필요 ❌
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//T, V는 number extends하니까 무조건 숫자일 것임.
public class Point <T extends Number, V extends Number>{
//generic
private T x;
private V y;
//getter
public T getX() {
return x;
}
public V getY() {
return y;
}
//constructor
public Point(T x, V y) {
this.x = x;
this.y = y;
}
//method
public Double caculateDistance(){
//downcast
Double num1= this.x.doubleValue();
Double num2= this.y.doubleValue();
return Math.sqrt((Math.pow(num1, 2)) + (Math.pow(num2, 2)));
}
}
This post is licensed under CC BY 4.0 by the author.