Post

[Java] Generic

[Java] Generic

πŸ’‘ 이 κ²Œμ‹œκΈ€μ€ κΉ€μ˜ν•œ κ°•μ‚¬λ‹˜μ˜ μžλ°” κ°•μ˜λ₯Ό μˆ˜κ°•ν•˜λ©° ν•™μŠ΅ν•œ λ‚΄μš©μ„ μ€‘μš”ν•œ ν‚€μ›Œλ“œ μ€‘μ‹¬μœΌλ‘œ μ •λ¦¬ν•œ 개인 ν•™μŠ΅ κΈ°λ‘μž…λ‹ˆλ‹€. 였직 κΈ°μ–΅ 볡기λ₯Ό μœ„ν•œ λͺ©μ μœΌλ‘œ μž‘μ„±λ˜μ—ˆμœΌλ©°, λͺ¨λ“  λ‚΄μš©μ„ ν¬ν•¨ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ ν•™μŠ΅ μžλ£Œλ‘œλŠ” μ ν•©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μž„μ‹œ μ €μž₯본이 λ‚ μ•„κ°€λŠ” κ²½μš°κ°€ μžˆμ–΄ demo둜 μ—…λ‘œλ“œ

Generic1

μ œλ„€λ¦­μ˜ 핡심은 μ‚¬μš©ν•  νƒ€μž…μ„ 미리 κ²°μ •ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 점이닀.
클래슀 λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•˜λŠ” νƒ€μž…μ„ 클래슀λ₯Ό μ •μ˜ν•˜λŠ” μ‹œμ μ— κ²°μ •ν•˜λŠ” 것이 μ•„λ‹ˆλΌ μ‹€μ œ μ‚¬μš©ν•˜λŠ” 생성 μ‹œμ μ— νƒ€μž…μ„ κ²°μ •ν•˜λŠ” 것이닀.

1
2
3
4
5
6
7
8
9
10
public class GenericBox<T> {

    private T value;
    public void set(T value) {
        this.value = value;
    }
    public T get() {
        return value;
    }
}

νƒ€μž… λ§€κ°œλ³€μˆ˜: GenericBox<T> μ—μ„œ T
νƒ€μž… 인자:
GenericBox<Integer> μ—μ„œ Integer
GenericBox<String> μ—μ„œ String

μ œλ„€λ¦­ 클래슀, μ œλ„€λ¦­ μΈν„°νŽ˜μ΄μŠ€λ₯Ό λͺ¨λ‘ ν•©μ³μ„œ μ œλ„€λ¦­ νƒ€μž…μ΄λΌ ν•œλ‹€.
GenericBox<T> λ₯Ό μ œλ„€λ¦­ νƒ€μž…μ΄λΌ ν•œλ‹€.

μ œλ„€λ¦­ λͺ…λͺ… κ΄€λ‘€

주둜 μ‚¬μš©ν•˜λŠ” ν‚€μ›Œλ“œλŠ” λ‹€μŒκ³Ό κ°™λ‹€.
E - Element
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types

νƒ€μž… 인자둜 κΈ°λ³Έν˜•μ€ μ‚¬μš©ν•  수 μ—†λ‹€
μ œλ„€λ¦­μ˜ νƒ€μž… 인자둜 κΈ°λ³Έν˜•(int , double ..)은 μ‚¬μš©ν•  수 μ—†λ‹€. λŒ€μ‹ μ— 래퍼 클래슀(Integer , Double )λ₯Ό μ‚¬μš©
ν•˜λ©΄ λœλ‹€.

1
GenericBox<Object> integerBox = new GenericBox<>();

Generic2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package generic.ex3;
import generic.animal.Animal;

public class AnimalHospitalV3<T extends Animal> {
    private T animal;

    public void set(T animal) {
        this.animal = animal;
    }

    public void checkup() {
        System.out.println(animal.getName());
        System.out.println(animal.getSize());
        animal.sound();
    }
    public T getBigger(T target) {
        return animal.getSize() > target.getSize() ? animal : target;
    }
}

μ—¬κΈ°μ„œ 핡심은 <T extends Animal> 이닀.
νƒ€μž… λ§€κ°œλ³€μˆ˜ T λ₯Ό Animal κ³Ό κ·Έ μžμ‹λ§Œ 받을 수 μžˆλ„λ‘ μ œν•œμ„ λ‘λŠ” 것이닀.
즉 T 의 μƒν•œμ΄ Animal 이 λ˜λŠ” 것이닀.

Generic Method

1
public static <T> T genericMethod(T t) { ... }

βœ” 클래슀 전체에 μ œλ„€λ¦­μ΄ ν•„μš”ν•˜μ§€ μ•Šμ§€λ§Œ,
βœ” νŠΉμ • λ©”μ„œλ“œμ—μ„œλ§Œ νƒ€μž…μ„ μœ μ—°ν•˜κ²Œ ν•˜κ³  싢을 λ•Œ μ‚¬μš©ν•¨

λ©”μ„œλ“œ μ•ˆμ—μ„œ νƒ€μž… λ§€κ°œλ³€μˆ˜ <T>λ₯Ό 직접 μ„ μ–Έν•˜κ³ , 이 νƒ€μž…μ„ νŒŒλΌλ―Έν„°λ‚˜ λ°˜ν™˜ νƒ€μž…μœΌλ‘œ μ‚¬μš©ν•˜λŠ” λ©”μ„œλ“œ

μ œλ„€λ¦­ λ©”μ„œλ“œλŠ” 클래슀 전체가 μ•„λ‹ˆλΌ νŠΉμ • λ©”μ„œλ“œ λ‹¨μœ„λ‘œ μ œλ„€λ¦­μ„ λ„μž…ν•  λ•Œ μ‚¬μš©ν•œλ‹€.

μ œλ„€λ¦­ λ©”μ„œλ“œμ˜ 핡심은 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” μ‹œμ μ— νƒ€μž… 인자λ₯Ό μ „λ‹¬ν•΄μ„œ νƒ€μž…μ„ μ§€μ •ν•˜λŠ” 것이닀. λ”°λΌμ„œ νƒ€μž…μ„ μ§€μ •ν•˜λ©΄μ„œ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package generic.ex4;

public class GenericMethod {
    // 1. κ·Έλƒ₯ Object둜 λ°›λŠ” 일반 λ©”μ„œλ“œ
    public static Object objMethod (Object obj) {
        System.out.println("object print: " + obj);
        return obj;
    }
    // 2. μ œλ„€λ¦­ λ©”μ„œλ“œ (νƒ€μž… νŒŒλΌλ―Έν„° T)
    public static <T> T genericMethod (T t) {
        System.out.println("generic print: " + t);
        return t;
    }
    // 3. μ œλ„€λ¦­ + νƒ€μž… μ œν•œ (TλŠ” Number λ˜λŠ” κ·Έ ν•˜μœ„ 클래슀만)
    public static <T extends Number> T numberMethod (T t) {
        System.out.println("bound print: " + t);
        return t;
    }
}

Generic Method - static, instance method

1
2
3
4
class Box<T> { //μ œλ„€λ¦­ νƒ€μž…
    static <V> V staticMethod2(V t) {} //static λ©”μ„œλ“œμ— μ œλ„€λ¦­ λ©”μ„œλ“œ λ„μž…
    <Z> Z instanceMethod2(Z z) {} //μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œμ— μ œλ„€λ¦­ λ©”μ„œλ“œ λ„μž… κ°€λŠ₯
}

static λ©”μ„œλ“œλŠ” ν΄λž˜μŠ€κ°€ λ‘œλ“œλ  λ•Œ λ©”λͺ¨λ¦¬μ— 올라였고,
이 μ‹œμ μ—” 클래슀의 μ œλ„€λ¦­ νƒ€μž… Tκ°€ 아직 κ²°μ •λ˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ—,
λ©”μ„œλ“œ μ•ˆμ—μ„œ <T> λ₯Ό 직접 μ„ μ–Έν•˜λ©΄ ν΄λž˜μŠ€μ™€ 상관없이 λ©”μ„œλ“œ 호좜 μ‹œμ μ— νƒ€μž…μ„ μ•Œμ•„μ„œ μ •ν•  수 있음.

<T>λŠ” νƒ€μž… λ§€κ°œλ³€μˆ˜ μ„ μ–Έ

1
2
3
`<T>`λŠ” β€œνƒ€μž…μ„ λ‚˜μ€‘μ— μ •ν•˜μžβ€λŠ” 뜻이고, 
ν΄λž˜μŠ€μ—μ„œ μ“°λ©΄ β€œκ°μ²΄ λ§Œλ“€ λ•Œ μ •ν•˜κ³ β€, 
λ©”μ„œλ“œμ—μ„œ μ“°λ©΄ β€œλ©”μ„œλ“œ ν˜ΈμΆœν•  λ•Œ μ •ν•œλ‹€." κ·Έ 뒀에 μ˜€λŠ” `T`λŠ” κ·Έ μ„ μ–Έν•œ νƒ€μž…μ„ 리턴 νƒ€μž…μœΌλ‘œ μ“°κ² λ‹€λŠ” 뜻 λ§€κ°œλ³€μˆ˜μ˜ `(T t)`λŠ” κ·Έ νƒ€μž…μ˜ 값을 λ°›μ•„ μ“°κ² λ‹€λŠ” 뜻

Generic Method - Type Parameter Bound

1
public static <T extends Number> T numberMethod(T t) {}

** Generic Type, Generic Method **

static methodλŠ” 클래슀의 Tλ₯Ό μ•Œ 수 μ—†κΈ° λ•Œλ¬Έμ— λ°˜λ“œμ‹œ <T>둜 μ œλ„€λ¦­ λ©”μ„œλ“œ 선언을 ν•΄μ•Ό ν•˜κ³ ,
Γ¬nstance methodλŠ” 이미 클래슀의 μ œλ„€λ¦­ νƒ€μž…μ΄ μ •ν•΄μ§„ μƒνƒœλΌμ„œ 클래슀의 Tλ“ , λ©”μ„œλ“œμ˜ Tλ“  λ‘˜ λ‹€ μ‚¬μš© κ°€λŠ₯ν•˜λ‹€!

Generic Type Generic Method 의 μš°μ„ μˆœμœ„

🌱

μŠ€ν”„λ§μ„ λΉ λ₯΄κ²Œ 배우기 μœ„ν•΄μ„œ 쀑급1편 κ°•μ˜μ˜ 일뢀λ₯Ό skip ν–ˆλ”λ‹ˆ ν—·κ°ˆλ¦¬λŠ” 뢀뢄이 생겼닀.

μ°μ°ν•˜κ²Œ λ„˜μ–΄κ°€λŠ”κ±Έ λͺ»ν•΄μ„œ λ”°λ‘œ κ³΅λΆ€ν•΄λ³΄κΈ°λ‘œ ~..

getClass().getName() μ—μ„œμ˜ getName() κ³Ό animal.getName() μ—μ„œμ˜ getName() 의 차이점을 λͺ¨λ₯΄κ² λ‹€λŠ” λ¬Έμ œμ˜€λ‹€.

** getClass() **

1
public final Class<?> getClass()

이건 μžλ°”μ—μ„œ λͺ¨λ“  객체가 μ‚¬μš©ν•  수 μžˆλŠ” λ©”μ„œλ“œκ³ , Object ν΄λž˜μŠ€μ— μ •μ˜λ˜μ–΄ μžˆλ‹€.

1
2
λ°˜ν™˜κ°’
Class<?>

즉, μžλ°”μ˜ β€œν΄λž˜μŠ€λ₯Ό ν‘œν˜„ν•˜λŠ”β€ 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.
이 κ°μ²΄λŠ” μžλ°” λ‚΄λΆ€μ—μ„œ β€œν΄λž˜μŠ€ μžμ²΄β€λ₯Ό μ„€λͺ…ν•˜λŠ” 메타 정보λ₯Ό λ‹΄κ³  μžˆλ‹€.

1
2
3
4
5
6
String s = "hello";

System.out.println(s.getClass());                  // class java.lang.String
System.out.println(s.getClass().getName());        // java.lang.String
System.out.println(s.getClass().getSimpleName());  // String
System.out.println(s.getClass().getSuperclass());  // class java.lang.Object

s.getClass()λŠ” 클래슀 자체λ₯Ό μ„€λͺ…ν•˜λŠ” 객체고,
s.getClass().getName()은 κ·Έ 클래슀의 μ΄λ¦„λ§Œ λ¬Έμžμ—΄λ‘œ κΊΌλ‚Έ 것이닀.

getClass().getName() μ—μ„œμ˜ getName()
이 경우의 getName()은 μ§„μ§œ λ‚΄μž₯ API λ©”μ„œλ“œ.
getName() β†’ Class 클래슀의 λ©”μ„œλ“œ (클래슀 이름을 λ¬Έμžμ—΄λ‘œ μ•Œλ €μ€Œ).

animal.getName() μ—μ„œμ˜ getName()
λ‚΄κ°€ Animal 클래슀 μ•ˆμ—μ„œ 직접 λ§Œλ“  일반 λ©”μ„œλ“œ

🌱 getName()만 μ“°λ©΄ μ•ˆ 되고, κΌ­ getClass().getName()처럼 써야 ν•˜λ‚˜?

getName()은 클래슀(Class 객체)에 μ •μ˜λœ λ©”μ„œλ“œμ§€, λ§Œλ“  객체(예: String, Animal λ“±) μžμ²΄μ—λŠ” getName()μ΄λΌλŠ” λ©”μ„œλ“œκ°€ λ°˜λ“œμ‹œ μžˆλŠ” 게 μ•„λ‹˜

κ·Έλž˜μ„œ getName()을 μ“°λ €λ©΄ λ¨Όμ € getClass()λ₯Ό 톡해 β€œν΄λž˜μŠ€λ₯Ό μ„€λͺ…ν•˜λŠ” 객체”λ₯Ό 가져와야 함.

1
s.getClass().getName()

”s 객체의 ν΄λž˜μŠ€κ°€ 뭐냐? β†’ κ·Έ 클래슀 κ°μ²΄μ—μ„œ 이름이 뭐냐?”

🌱 Animal 클래슀 λ‚΄λΆ€μ˜ getName() 이 μ˜€λ²„λΌμ΄λ“œκ°€ μ•„λ‹Œ 이유

getClass().getName()의 getName()은 Class 클래슀의 λ‚΄μž₯ λ©”μ„œλ“œ,
animal.getName()의 getName()은 λ„€κ°€ Animal ν΄λž˜μŠ€μ—μ„œ λ§Œλ“  일반 λ©”μ„œλ“œ 이닀.

이름이 같을 뿐 μ™„μ „νžˆ λ‹€λ₯Έ 쑴재이기 λ•Œλ¬Έμ— ( 상속 관계도 μ—†κ³ , λ‹€λ₯Έ ν΄λž˜μŠ€μ— μžˆμœΌλ―€λ‘œ μ „ν˜€ 관련이 μ—†μŒ ) μ˜€λ²„λΌμ΄λ“œ 에 ν•΄λ‹Ήλ˜μ§€ μ•ŠλŠ”λ‹€.

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
package generic.animal;

public class Animal {

    private String name;
    private int size;

    public Animal(String name, int size) {
        this.name = name;
        this.size = size;
    }
    public String getName() {
        return name;
    }

    public int getSize() {
        return size;
    }
    public void sound() {
        System.out.println("동물 울음 μ†Œλ¦¬");
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", size=" + size +
                '}';
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package generic.ex4;
import generic.animal.Animal;

public class ComplexBox<T extends Animal> {
    private T animal;

    public void set(T animal) {
        this.animal = animal;
    }

    public <T> T printAndReturn(T t) {
        System.out.println("animal.className: " + animal.getClass().getName());
        System.out.println("t.className: " + t.getClass().getName());
        // t.getName(); // 호좜 λΆˆκ°€ λ©”μ„œλ“œλŠ” <T> νƒ€μž…μ΄λ‹€. <T extends Animal> νƒ€μž…μ΄ μ•„λ‹ˆλ‹€.
        return t;
    }
}

클래슀의 <T>와 λ©”μ„œλ“œμ˜ <T>λŠ” μ™„μ „νžˆ λ‹€λ₯Έ Tλ‹€.

μ œλ„€λ¦­ νƒ€μž…(T) 이 ν΄λž˜μŠ€μ— 이미 μžˆμ–΄λ„,
λ©”μ„œλ“œμ—μ„œ <T>λ₯Ό λ‹€μ‹œ μ„ μ–Έν•˜λ©΄ κ·Έ λ©”μ„œλ“œ μ•ˆμ—μ„œλŠ” 그게 μš°μ„  μ μš©λœλ‹€.

κ·Έλž˜μ„œ λ©”μ„œλ“œμ˜ <T>λŠ” 클래슀의 T와 μ™„μ „ λ³„κ°œμ΄λ©°, 이름이 같아도 자기 μ˜μ—­μ—μ„œλŠ” λ©”μ„œλ“œμ˜ Tκ°€ μš°μ„ μ΄λ‹€.

This post is licensed under CC BY 4.0 by the author.