...

์ ๋ค๋ฆญ (Generics) ์ด๋
์๋ฐ์์ ์ ๋ค๋ฆญ(Generics)์ ํด๋์ค ๋ด๋ถ์์ ์ฌ์ฉํ ๋ฐ์ดํฐ ํ์ ์ ์ธ๋ถ์์ ์ง์ ํ๋ ๊ธฐ๋ฒ์ ์๋ฏธํ๋ค. ๊ฐ์ฒด๋ณ๋ก ๋ค๋ฅธ ํ์ ์ ์๋ฃ๊ฐ ์ ์ฅ๋ ์ ์๋๋ก ํ๋ค.
์๋ฐ์์ ๋ฐฐ์ด๊ณผ ํจ๊ป ์์ฃผ ์ฐ์ด๋ ์๋ฃํ์ด ๋ฆฌ์คํธ(List)์ธ๋ฐ, ๋ค์๊ณผ ๊ฐ์ด ํด๋์ค ์ ์ธ ๋ฌธ๋ฒ์ ๊บพ์ ๊ดํธ <> ๋ก ๋์ด์๋ ์ฝ๋ ํํ๋ฅผ ํ๋ฒ ์ฏค์ ๋ดค์ ๊ฒ์ด๋ค.
ArrayList<String> list = new ArrayList<>();
์ ๊บพ์ ๊ดํธ๊ฐ ๋ฐ๋ก ์ ๋ค๋ฆญ์ด๋ค. ๊ดํธ ์์๋ ํ์ ๋ช ์ ๊ธฐ์ฌํ๋ค. ๊ทธ๋ฌ๋ฉด ์ ๋ฆฌ์คํธ ํด๋์ค ์๋ฃํ์ ํ์ ์ String ํ์ ์ผ๋ก ์ง์ ๋์ด ๋ฌธ์์ด ๋ฐ์ดํฐ๋ง ๋ฆฌ์คํธ์ ์ ์ฌํ ์ ์๊ฒ ๋๋ค.
์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๋ฐฐ์ด๊ณผ ๋ฆฌ์คํธ์ ์ ์ธ๋ฌธ ํํ๋ฅผ ๋น๊ตํด๋ณด๋ฉด ์ดํดํ๊ธฐ ์ฌ์ธ ๊ฒ์ด๋ค. ์ ์ธํ๋ ํค์๋๋ ๋ฌธ๋ฒ ์์๊ฐ ๋ค๋ฅผ๋ฟ, ๊ฒฐ๊ตญ ์๋ฃํ๋ช ์ ์ ์ธํ๊ณ ์๋ฃํ์ ํ์ ์ ์ง์ ํ๋ค๋ ์ ์ ๊ฐ๋ค๊ณ ๋ณผ ์ ์๋ค.

์ด์ฒ๋ผ ์ ๋ค๋ฆญ์ ๋ฐฐ์ด์ ํ์ ์ ์ง์ ํ๋ฏ์ด ๋ฆฌ์คํธ ์๋ฃํ ๊ฐ์ ์ปฌ๋ ์ ํด๋์ค๋ ๋ฉ์๋์์ ์ฌ์ฉํ ๋ด๋ถ ๋ฐ์ดํฐ ํ์ (type)์ ํ๋ผ๋ฏธํฐ(parameter) ์ฃผ๋ฏ์ด ์ธ๋ถ์์ ์ง์ ํ๋ ์ด๋ฅธ๋ฐ ํ์ ์ ๋ณ์ํ ํ ๊ธฐ๋ฅ์ด๋ผ๊ณ ์ดํดํ๋ฉด ๋๋ค.
์ฐ๋ฆฌ๊ฐ ๋ณ์๋ฅผ ์ ์ธํ ๋ ๋ณ์์ ํ์ ์ ์ง์ ํด์ฃผ๋ฏ์ด, ์ ๋ค๋ฆญ์ ๊ฐ์ฒด(Object)์ ํ์ ์ ์ง์ ํด์ฃผ๋ ๊ฒ์ด๋ผ๊ณ ๋ณด๋ฉด ๋๋ค.
์ ๋ค๋ฆญ ํ์ ๋งค๊ฐ๋ณ์
์์์ ๋ณด๋ค์ํผ, ์ ๋ค๋ฆญ์ <> ๊บพ์ ๊ดํธ ํค์๋๋ฅผ ์ฌ์ฉํ๋๋ฐ ์ด๋ฅผ ๋ค์ด์๋ชฌ๋ ์ฐ์ฐ์๋ผ๊ณ ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ๊บพ์ ๊ดํธ ์์ ์๋ณ์ ๊ธฐํธ๋ฅผ ์ง์ ํจ์ผ๋ก์จ ํ๋ผ๋ฏธํฐํ ํ ์ ์๋ค. ์ด๊ฒ์ ๋ง์น ๋ฉ์๋๊ฐ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋น์ทํ์ฌ ์ ๋ค๋ฆญ์ ํ์
๋งค๊ฐ๋ณ์(parameter) / ํ์
๋ณ์ ๋ผ๊ณ ๋ถ๋ฅธ๋ค.

ํ์ ํ๋ผ๋ฏธํฐ ์ ์
์ด ํ์ ๋งค๊ฐ๋ณ์๋ ์ ๋ค๋ฆญ์ ์ด์ฉํ ํด๋์ค๋ ๋ฉ์๋๋ฅผ ์ค๊ณํ ๋ ์ฌ์ฉ๋๋ค.
์๋ฅผ๋ค์ด ๋ค์ ์ฝ๋๋ ์ ๋ค๋ฆญ์ ๊ฐ๋ฏธํ ํด๋์ค๋ฅผ ์ ์ํ ์ฝ๋์ด๋ค. ํด๋์ค๋ช
์์ <T> ๊ธฐํธ๋ก ์ ๋ค๋ฆญ์ ๋ถ์ฌ์ค ๊ฑธ ๋ณผ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋์ค ๋ด๋ถ์์ ์๋ณ์ ๊ธฐํธ T ๋ฅผ ํด๋์ค ํ๋์, ๋ฉ์๋์ ๋งค๊ฐ๋ณ์์ ํ์
์ผ๋ก ์ง์ ๋์ด ์๋ค.
class FruitBox<T> {
List<T> fruits = new ArrayList<>();
public void add(T fruit) {
fruits.add(fruit);
}
}
์ ๋ค๋ฆญ ํด๋์ค๋ฅผ ๋ง๋ค์์ผ๋ฉด ์ด๋ฅผ ์ธ์คํด์คํ ํด๋ณด์. ๋ง์น ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ ํด์ ๋ณด๋ด๋ ๊ฒ ์ฒ๋ผ ์์ฑ ์ฝ๋์์ ๊บพ์ ๊ดํธ ์์ ์ง์ ํด์ฃผ๊ณ ์ถ์ ํ์
๋ช
์ ํ ๋นํด์ฃผ๋ฉด, ์ ๋ค๋ฆญ ํด๋์ค ์ ์ธ๋ฌธ ๋ถ๋ถ์ผ๋ก ๊ฐ์ ํ์
ํ๋ผ๋ฏธํฐ T ๊ฐ ์ง์ ๋ ํ์
์ผ๋ก ๋ชจ๋ ๋ณํ๋์ด ํด๋์ค์ ํ์
์ด ์ง์ ๋๊ฒ ๋๋ ๊ฒ์ด๋ค.
// ์ ๋ค๋ฆญ ํ์
๋งค๊ฐ๋ณ์์ ์ ์ ํ์
์ ํ ๋น
FruitBox<Integer> intBox = new FruitBox<>();
// ์ ๋ค๋ฆญ ํ์
๋งค๊ฐ๋ณ์์ ์ค์ ํ์
์ ํ ๋น
FruitBox<Double> intBox = new FruitBox<>();
// ์ ๋ค๋ฆญ ํ์
๋งค๊ฐ๋ณ์์ ๋ฌธ์์ด ํ์
์ ํ ๋น
FruitBox<String> intBox = new FruitBox<>();
// ํด๋์ค๋ ๋ฃ์ด์ค ์ ์๋ค. (Apple ํด๋์ค๊ฐ ์๋ค๊ณ ๊ฐ์ )
FruitBox<Apple> intBox = new FruitBox<Apple>();
์ด๋ฅผ ๊ทธ๋ฆผ์ผ๋ก ํํํด๋ณด๋ฉด, ๋ค์๊ณผ ๊ฐ์ด ์ ๋ค๋ฆญ ํ์
์ ํ๊ฐ ํํด์ง๊ณ ๋ณด๋ฉด ๋๋ค. <T> ๋ถ๋ถ์์ ์คํ๋ถ์์ ํ์
์ ๋ฐ์์ ๋ด๋ถ์์ T ํ์
์ผ๋ก ์ง์ ํ ๋ฉค๋ฒ๋ค์๊ฒ ์ ํํ์ฌ ํ์
์ด ๊ตฌ์ฒด์ ์ผ๋ก ์ค์ ๋๋ ๊ฒ์ด๋ค. ์ด๋ฅผ ์ ๋ฌธ ์ฉ์ด๋ก ๊ตฌ์ฒดํ(Specialization) ๋ผ๊ณ ํ๋ค.

ํ์ ํ๋ผ๋ฏธํฐ ์๋ต
์ ๋ค๋ฆญ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ๋ฌธ๋ฒ ํํ๋ฅผ ๋ณด๋ฉด ์์ชฝ ๋ ๊ตฐ๋ฐ์ ๊บพ์ ๊ดํธ ์ ๋ค๋ฆญ ํ์ ์ ์ง์ ํจ์ ๋ณผ ์ ์๋ค. ํ์ง๋ง ๋งจ ์์์ ํด๋์ค๋ช ๊ณผ ํจ๊ป ํ์ ์ ์ง์ ํด ์ฃผ์๋๋ฐ ๊ตณ์ด ์์ฑ์๊น์ง ์ ๋ค๋ฆญ์ ์ง์ ํด ์ค ํ์๊ฐ ์๋ค. (์ค๋ณต)
๋ฐ๋ผ์ jdk 1.7 ๋ฒ์ ์ดํ๋ถํฐ, new ์์ฑ์ ๋ถ๋ถ์ ์ ๋ค๋ฆญ ํ์ ์ ์๋ตํ ์ ์๊ฒ ๋์๋ค. ์ ๋ค๋ฆญ ๋๋ฆ๋๋ก ํ์ ์ถ๋ก ์ ํด์ ์๋ต ๋ ๊ณณ์ ๋ฃ์ด์ฃผ๊ธฐ ๋๋ฌธ์ ๋ฌธ์ ๊ฐ ์๋ ๊ฒ์ด๋ค.
FruitBox<Apple> intBox = new FruitBox<Apple>();
// ๋ค์๊ณผ ๊ฐ์ด new ์์ฑ์ ๋ถ๋ถ์ ์ ๋ค๋ฆญ์ ํ์
๋งค๊ฐ๋ณ์๋ ์๋ตํ ์ ์๋ค.
FruitBox<Apple> intBox = new FruitBox<>();
ํ์ ํ๋ผ๋ฏธํฐ ํ ๋น ๊ฐ๋ฅ ํ์
์ ๋ค๋ฆญ์์ ํ ๋น ๋ฐ์ ์ ์๋ ํ์ ์ Reference ํ์ ๋ฟ์ด๋ค. ์ฆ, intํ ์ด๋ doubleํ ๊ฐ์ ์๋ฐ ์์ ํ์ (Primitive Type)์ ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ๋ก ๋๊ธธ ์ ์๋ค๋ ๋ง์ด๋ค.
์ฐ๋ฆฌ๊ฐ Wrapper ํด๋์ค์ ๋ํด ๊ณต๋ถํ ๋ intํ, doubleํ์ด ์ด๋ฏธ ์กด์ฌํ๋๋ฐ, ์ ๊ตณ์ด ๋๊ฐ์ ์ญํ ์ ํ๋ Integerํ, Doubleํ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋จ์๊น ๊ณ ๋ฏผ์ ํด๋ณธ์ ์ด ์์์ ๊ฒ์ด๋ค. ๋ฐ๋ก ์ด๋ ์ฌ์ฉํ๋ ๊ฒ์ด๋ผ๊ณ ์ดํดํ๋ฉด ๋๋ค.
๋ฐ๋ก ์ ์์ด ๋์ง๋ ์๊ฒ ์ง๋ง, ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์์๋ ๋ชจ๋ ๊ฒ์ด ๊ฐ์ฒด๋ก ํต์ ํ๊ธฐ ๋๋ฌธ์ ๋ฒ๊ฑฐ๋กญ๋๋ผ๋ ์ต์ํด ์ง์ด์ผ ํ๋ค.
// ๊ธฐ๋ณธ ํ์
int๋ ์ฌ์ฉ ๋ถ๊ฐ !!!
List<int> intList = new List<>();
// Wrapper ํด๋์ค๋ก ๋๊ฒจ์ฃผ์ด์ผ ํ๋ค. (๋ด๋ถ์์ ์๋์ผ๋ก ์ธ๋ฐ์ฑ๋์ด ์์ ํ์
์ผ๋ก ์ด์ฉ๋จ)
List<Integer> integerList = new List<>();
๋ํ ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ์ ํด๋์ค๊ฐ ํ์ ์ผ๋ก ์จ๋ค๋ ๊ฒ์, ํด๋์ค๋ผ๋ฆฌ ์์์ ํตํด ๊ด๊ณ๋ฅผ ๋งบ๋ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๋คํ์ฑ ์๋ฆฌ๊ฐ ๊ทธ๋๋ก ์ ์ฉ์ด ๋๋ค๋ ์๋ฆฌ์ด๋ค.
์๋ ์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ํ์
ํ๋ผ๋ฏธํฐ๋ก <Fruit> ๋ก ์ง์ ํ์ง๋ง ์
์บ์คํ
์ ํตํด ๊ทธ ์์ ๊ฐ์ฒด๋ ํ ๋น์ด ๋จ์ ๋ณผ ์ ์๋ค.

class Fruit { }
class Apple extends Fruit { }
class Banana extends Fruit { }
class FruitBox<T> {
List<T> fruits = new ArrayList<>();
public void add(T fruit) {
fruits.add(fruit);
}
}
public class Main {
public static void main(String[] args) {
FruitBox<Fruit> box = new FruitBox<>();
// ์ ๋ค๋ฆญ ํ์
์ ๋คํ์ฑ ์๋ฆฌ๊ฐ ๊ทธ๋๋ก ์ ์ฉ๋๋ค.
box.add(new Fruit());
box.add(new Apple());
box.add(new Banana());
}
}
๋ณต์ ํ์ ํ๋ผ๋ฏธํฐ
์ ๋ค๋ฆญ์ ๋ฐ๋์ ํ๊ฐ๋ง ์ฌ์ฉํ๋ผ๋ ๋ฒ์ ์๋ค. ๋ง์ผ ํ์ ์ง์ ์ด ์ฌ๋ฌ๊ฐ๊ฐ ํ์ํ ๊ฒฝ์ฐ 2๊ฐ, 3๊ฐ ์ผ๋ง๋ ์ง ๋ง๋ค ์ ์๋ค.
์ ๋ค๋ฆญ ํ์
์ ๊ตฌ๋ถ์ ๊บฝ์ ๊ดํธ ์์์ ์ฝํ(,)๋ก ํ๋ฉฐ <T, U> ์ ๊ฐ์ ํ์์ ํตํด ๋ณต์ ํ์
ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ ํ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ ๋น์ฐํ ํด๋์ค ์ด๊ธฐํํ ๋ ์ ๋ค๋ฆญ ํ์
์ ๋๊ฐ๋ฅผ ๋๊ฒจ์ฃผ์ด์ผ ํ๋ค.
import java.util.ArrayList;
import java.util.List;
class Apple {}
class Banana {}
class FruitBox<T, U> {
List<T> apples = new ArrayList<>();
List<U> bananas = new ArrayList<>();
public void add(T apple, U banana) {
apples.add(apple);
bananas.add(banana);
}
}
public class Main {
public static void main(String[] args) {
// ๋ณต์ ์ ๋ค๋ฆญ ํ์
FruitBox<Apple, Banana> box = new FruitBox<>();
box.add(new Apple(), new Banana());
box.add(new Apple(), new Banana());
}
}
์ค์ฒฉ ํ์ ํ๋ผ๋ฏธํฐ
์ ๋ค๋ฆญ ๊ฐ์ฒด๋ฅผ ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๋ ํ์๋ ํํํ ์ ์๋ค.
ArrayList ์์ฒด๋ ํ๋์ ํ์ ์ผ๋ก์จ ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ๊ฐ ๋ ์ ์๊ธฐ ๋๋ฌธ์ ์ด๋ ๊ฒ ์ค์ฒฉ ํ์์ผ๋ก ์ฌ์ฉํ ์ ์๋ ๊ฒ์ด๋ค.
public static void main(String[] args) {
// LinkedList<String>์ ์์๋ก์ ์ ์ฅํ๋ ArrayList
ArrayList<LinkedList<String>> list = new ArrayList<LinkedList<String>>();
LinkedList<String> node1 = new LinkedList<>();
node1.add("aa");
node1.add("bb");
LinkedList<String> node2 = new LinkedList<>();
node2.add("11");
node2.add("22");
list.add(node1);
list.add(node2);
System.out.println(list);
}

ํ์ ํ๋ผ๋ฏธํฐ ๊ธฐํธ ๋ค์ด๋ฐ
์ง๊ธ๊น์ง ์ ๋ค๋ฆญ ๊ธฐํธ๋ฅผ <T> ์ ๊ฐ์ด ์จ์ ํํํ์ง๋ง ์ฌ์ค ์๋ณ์ ๊ธฐํธ๋ ๋ฌธ๋ฒ์ ์ผ๋ก ์ ํด์ง ๊ฒ์ด ์๋ค.
๋ค๋ง ์ฐ๋ฆฌ๊ฐ for๋ฌธ์ ์ด์ฉํ ๋ ๋ฃจํ ๋ณ์๋ฅผ i ๋ก ์ง์ ํด์ ์ฌ์ฉํ๋ฏ์ด, ์ ๋ค๋ฆญ์ ํํ ๋ณ์๋ฅผ T ๋ก ํํํ๋ค๊ณ ๋ณด๋ฉด ๋๋ค. ๋ง์ผ ๋๋ฒ์งธ, ์ธ๋ฒ์งธ ์ ๋ค๋ฆญ์ด ํ์ํ๋ค๊ณ ๋ณด๋ฉด for๋ฌธ์ j๋ k ๊ฐ์ด S, U ๋ก ์ด์ด๋๊ฐ๋ค.
๋ช
๋ช
ํ๊ณ ์ถ์๋๋ก ์๋ฌด ๋จ์ด๋ ๋ฃ์ด๋ ๋ฌธ์ ๋ ์์ง๋ง, ๋์ค์ ์ผ๋ก ํตํ๋ ํต์์ ์ธ ๋ค์ด๋ฐ์ด ์์ผ๋ฉด ๊ฐ๋ฐ์ด ์ฉ์ดํด ์ง๊ธฐ ๋๋ฌธ์ ์๋ ํํ ๊ฐ์ ์๋ฌต์ ์ธ ๊ท์น(convention)์ด ์กด์ฌํ๋ค. ์๋ฅผ๋ค์ด ์์ ์์ ์ฌ์ฉ๋ T ๋ฅผ ํ์
๋ณ์(type variable)๋ผ๊ณ ํ๋ฉฐ, ์์์ ์ฐธ์กฐํ ํ์
์ ์๋ฏธํ๋ค.
ํ์ | ์ค๋ช |
<T> | ํ์ (Type) |
<E> | ์์(Element), ์๋ฅผ ๋ค์ด List |
<K> | ํค(Key), ์๋ฅผ ๋ค์ด Map<k, v> |
<V> | ๋ฆฌํด ๊ฐ ๋๋ ๋งคํ๋ ๊ฐ(Variable) |
<N> | ์ซ์(Number) |
<S, U, V> | 2๋ฒ์งธ, 3๋ฒ์งธ, 4๋ฒ์งธ์ ์ ์ธ๋ ํ์ |
์ ๋ค๋ฆญ ์ฌ์ฉ ์ด์ ์ ์ด์
1. ์ปดํ์ผ ํ์์ ํ์ ๊ฒ์ฌ๋ฅผ ํตํด ์์ธ ๋ฐฉ์ง
์๋ฐ์์ ์ ๋ค๋ฆญ(Generic)์ ์๋ฐ 1.5์ ์ถ๊ฐ๋ ์คํ์ด๋ค. ๊ทธ๋์ JDK 1.5 ์ด์ ์์๋ ์ฌ๋ฌ ํ์ ์ ๋ค๋ฃจ๊ธฐ ์ํด ์ธ์๋ ๋ฐํ๊ฐ์ผ๋ก Object ํ์ ์ ์ฌ์ฉํ์์๋ค. ํ์ง๋ง Object๋ก ํ์ ์ ์ ์ธํ ๊ฒฝ์ฐ ๋ฐํ๋ Object ๊ฐ์ฒด๋ฅผ ๋ค์ ์ํ๋ ํ์ ์ผ๋ก ์ผ์ผํ ํ์ ๋ณํ์ ํด์ผ ํ๋ฉฐ, ๋ฐํ์ ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ๋ ์กด์ฌํ๊ฒ ๋๋ค.
์๋ ์์ ์์ Object ํ์ ์ผ๋ก ์ ์ธํ ๋ฐฐ์ด์ Apple ๊ณผ Banana ๊ฐ์ฒด ํ์ ์ ์ ์ฅํ๊ณ ์ด๋ฅผ ๋ค์ ๊ฐ์ ธ์ค๋ ์์ ์ด๋ค.
class Apple {}
class Banana {}
class FruitBox {
// ๋ชจ๋ ํด๋์ค ํ์
์ ๋ฐ๊ธฐ ์ํด ์ต๊ณ ์กฐ์์ธ Object ํ์
์ผ๋ก ์ค์
private Object[] fruit;
public FruitBox(Object[] fruit) {
this.fruit = fruit;
}
public Object getFruit(int index) {
return fruit[index];
}
}
public static void main(String[] args) {
Apple[] arr = {
new Apple(),
new Apple()
};
FruitBox box = new FruitBox(arr);
Apple apple = (Apple) box.getFruit(0);
Banana banana = (Banana) box.getFruit(1);
}

๊ทธ๋ฐ๋ฐ ์คํํด๋ณด๋ฉด ์์ ๊ฐ์ด ClassCastException ๋ฐํ์ ์๋ฌ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค. ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ฌ๋ ํ๋ณํ๋ ์ ํด์ฃผ์ด ๋ฌธ์ ๊ฐ ์๋ ๊ฒ ๊ฐ์๋ฐ ๋ฌด์์ด ๋ฌธ์ ์ผ๊น?
์์ธ์ ๊ฐ๋จํ๋ค. Apple ๊ฐ์ฒด ํ์ ์ ๋ฐฐ์ด์ FruitBox์ ๋ฃ์๋๋ฐ, ๊ฐ๋ฐ์๊ฐ ์ฐฉ๊ฐํ๊ณ Banana๋ฅผ ํ๋ณํํ์ฌ ๊ฐ์ ธ์ค๋ ค๊ณ ํ์๊ธฐ ๋๋ฌธ์ ์๊ธด ํ์์ด๋ค. ๋ฏธ๋ฆฌ ์ฝ๋์์ ๋นจ๊ฐ์ค๋ก ์๋ ค์คฌ์ผ๋ฉด ์ข๊ฒ ์ง๋ง ๋ณด๋ค์ํผ ๊นจ๋ํ๋ค.

์ ๋ค๋ฆญ์ ์ด์ฉํ๋ฉด ์ด๋ฐ ์ด์ฒ๊ตฌ๋ ์๋ ์ค์๋ฅผ ๋ฏธ์ฐ์ ๋ฐฉ์ง๋ฅผ ํ ์ ์๋ค. ์๋ํ๋ฉด ์ฝ๋๋ฅผ ์คํํ๊ธฐ์ ์ปดํ์ผ ํ์์ ๋ฏธ๋ฆฌ ์๋ฌ๋ฅผ ์ฐพ์ ์๋ ค์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
class FruitBox<T> {
private T[] fruit;
public FruitBox(T[] fruit) {
this.fruit = fruit;
}
public T getFruit(int index) {
return fruit[index];
}
}
public static void main(String[] args) {
Apple[] arr = {
new Apple(),
new Apple()
};
FruitBox<Apple> box = new FruitBox<>(arr);
Apple apple = (Apple) box.getFruit(0);
Banana banana = (Banana) box.getFruit(1);
}

์ด ์ฒ๋ผ ์ ๋ค๋ฆญ์ ํด๋์ค๋ ๋ฉ์๋๋ฅผ ์ ์ํ ๋ ํ์ ํ๋ผ๋ฏธํฐ๋ก ๊ฐ์ฒด์ ์๋ธ ํ์ ์ ์ง์ ํด์ค์ผ๋ก์จ, ์๋ชป๋ ํ์ ์ด ์ฌ์ฉ๋ ์ ์๋ ๋ฌธ์ ๋ฅผ ์ปดํ์ผ ๊ณผ์ ์์ ์ ๊ฑฐํ์ฌ ๊ฐ๋ฐ์ ์ฉ์ดํ๊ฒ ํด์ค๋ค.
2. ๋ถํ์ํ ์บ์คํ ์ ์์ ์ฑ๋ฅ ํฅ์
์์ ์์ ์ฝ๋์์ Apple ๋ฐฐ์ด์ FruitBox์ Object ๋ฐฐ์ด ๊ฐ์ฒด์ ๋ฃ๊ณ , ๋ฐฐ์ด ์์๋ฅผ ๊ฐ์ ธ์ฌ๋ ๋ฐ๋์ ๋ค์ด ์บ์คํ (down casting)์ ํตํด ๊ฐ์ ธ์์ผ ํ๋ค. ์ด๋ ๊ณง ์ถ๊ฐ์ ์ธ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ๋ ๊ฒ๊ณผ ๊ฐ๋ค.
Apple[] arr = { new Apple(), new Apple(), new Apple() };
FruitBox box = new FruitBox(arr);
// ๊ฐ์ ธ์จ ํ์
์ด Object ํ์
์ด๊ธฐ ๋๋ฌธ์ ์ผ์ผํ ๋ค์ด์บ์คํ
์ ํด์ผํจ - ์ธ๋ฐ์๋ ์ฑ๋ฅ ๋ญ๋น
Apple apple1 = (Apple) box.getFruit(0);
Apple apple2 = (Apple) box.getFruit(1);
Apple apple3 = (Apple) box.getFruit(2);
๋ฐ๋ฉด ์ ๋ค๋ฆญ์ ๋ฏธ๋ฆฌ ํ์ ์ ์ง์ & ์ ํํด ๋๊ธฐ ๋๋ฌธ์ ํ ๋ณํ(Type Casting)์ ๋ฒ๊ฑฐ๋ก์์ ์ค์ผ ์ ์์ผ๋ฉฐ, ํ์ ๊ฒ์ฌ์ ๋ค์ด๊ฐ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ค์ผ ์ ์๊ณ ๋๋ถ์ด ๊ฐ๋ ์ฑ๋ ์ข์์ง๋ค.
// ๋ฏธ๋ฆฌ ์ ๋ค๋ฆญ ํ์
ํ๋ผ๋ฏธํฐ๋ฅผ ํตํด ํ(type)์ ์ง์ ํด๋์๊ธฐ ๋๋ฌธ์ ๋ณ๋์ ํ๋ณํ์ ํ์์๋ค.
FruitBox<Apple> box = new FruitBox<>(arr);
Apple apple = box.getFruit(0);
Apple apple = box.getFruit(1);
Apple apple = box.getFruit(2);
์ ๋ค๋ฆญ ์ฌ์ฉ ์ฃผ์์ฌํญ
1. ์ ๋ค๋ฆญ ํ์ ์ ๊ฐ์ฒด๋ ์์ฑ์ด ๋ถ๊ฐ
์ ๋ค๋ฆญ ํ์
์์ฒด๋ก ํ์
์ ์ง์ ํ์ฌ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅ ํ๋ค. ์ฆ, new ์ฐ์ฐ์ ๋ค์ ์ ๋ค๋ฆญ ํ์
ํ๋ผ๋ฏธํฐ๊ฐ ์ฌ์๋ ์๋ค.
class Sample<T> {
public void someMethod() {
// Type parameter 'T' cannot be instantiated directly
T t = new T();
}
}
2. static ๋ฉค๋ฒ์ ์ ๋ค๋ฆญ ํ์ ์ด ์ฌ์ ์์
์๋ ์ฒ๋ผ static ๋ณ์์ ๋ฐ์ดํฐ ํ์ ์ผ๋ก ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ๊ฐ ์ฌ์๋ ์๋ค. ์๋ํ๋ฉด static ๋ฉค๋ฒ๋ ํด๋์ค๊ฐ ๋์ผํ๊ฒ ๊ณต์ ํ๋ ๋ณ์๋ก์ ์ ๋ค๋ฆญ ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ธฐ๋ ์ ์ ์ด๋ฏธ ์๋ฃ ํ์ ์ด ์ ํด์ ธ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ฆ, ๋ ผ๋ฆฌ์ ์ธ ์ค๋ฅ์ธ ๊ฒ์ด๋ค.
class Student<T> {
private String name;
private int age = 0;
// static ๋ฉ์๋์ ๋ฐํ ํ์
์ผ๋ก ์ฌ์ฉ ๋ถ๊ฐ
public static T addAge(int n) {
}
}

class Student<T> {
private String name;
private int age = 0;
// static ๋ฉ์๋์ ๋งค๊ฐ๋ณ์ ํ์
์ผ๋ก ์ฌ์ฉ ๋ถ๊ฐ
public static void addAge(T n) {
}
}

3. ์ ๋ค๋ฆญ์ผ๋ก ๋ฐฐ์ด ์ ์ธ ์ฃผ์์
๊ธฐ๋ณธ์ ์ผ๋ก ์ ๋ค๋ฆญ ํด๋์ค ์์ฒด๋ฅผ ๋ฐฐ์ด๋ก ๋ง๋ค ์๋ ์๋ค.
class Sample<T> {
}
public class Main {
public static void main(String[] args) {
Sample<Integer>[] arr1 = new Sample<>[10];
}
}

ํ์ง๋ง ์ ๋ค๋ฆญ ํ์ ์ ๋ฐฐ์ด ์ ์ธ์ ํ์ฉ๋๋ค.
์์ ์๊ณผ ์ฐจ์ด์ ์ ๋ฐฐ์ด์ ์ ์ฅํ Sample ๊ฐ์ฒด์ ํ์
ํ๋ผ๋ฏธํฐ๋ฅผ Integer ๋ก ์ง์ ํ๋ค๋ ๋ป์ด๋ค. ์ฆ, new Sample<Integer>() ์ธ์คํด์ค๋ ์ ์ฅ์ด ๊ฐ๋ฅํ๋ฉฐ, new Sample<String>() ์ธ์คํด์ค๋ ์ ์ฅ์ด ๋ถ๊ฐ๋ฅํ๋ค๋ ์๋ฆฌ์ด๋ค.
class Sample<T> {
}
public class Main {
public static void main(String[] args) {
// new Sample<Integer>() ์ธ์คํด์ค๋ง ์ ์ฅํ๋ ๋ฐฐ์ด์ ๋ํ๋
Sample<Integer>[] arr2 = new Sample[10];
// ์ ๋ค๋ฆญ ํ์
์ ์๋ตํด๋ ์์์ ์ด๋ฏธ ์ ์ํ๊ธฐ ๋๋ฌธ์ Integer ๊ฐ ์๋์ผ๋ก ์ถ๋ก ๋จ
arr2[0] = new Sample<Integer>();
arr2[1] = new Sample<>();
// ! Integer๊ฐ ์๋ ํ์
์ ์ ์ฅ ๋ถ๊ฐ๋ฅ
arr2[2] = new Sample<String>();
}
}
์ ๋ค๋ฆญ ๊ฐ์ฒด ๋ง๋ค์ด๋ณด๊ธฐ
์ ๋ค๋ฆญ์ ์ด์ฉํด ์ง์ ํด๋์ค์ ์ธํฐํ์ด์ค, ๋ฉ์๋๋ฅผ ๋ง๋ค์ด๋ณด๊ณ ์ฌ์ฉํด๋ณด๋ ์๊ฐ์ ๊ฐ์ ธ๋ณด์.
์ ๋ค๋ฆญ ํด๋์ค
ํด๋์ค ์ ์ธ๋ฌธ ์์ ์ ๋ค๋ฆญ ํ์ ๋งค๊ฐ๋ณ์๊ฐ ์ฐ์ด๋ฉด, ์ด๋ฅผ ์ ๋ค๋ฆญ ํด๋์ค๋ผ๊ณ ํ๋ค.
class Sample<T> {
private T value; // ๋ฉค๋ฒ ๋ณ์ val์ ํ์
์ T ์ด๋ค.
// T ํ์
์ ๊ฐ val์ ๋ฐํํ๋ค.
public T getValue() {
return value;
}
// T ํ์
์ ๊ฐ์ ๋ฉค๋ฒ ๋ณ์ val์ ๋์
ํ๋ค.
public void setValue(T value) {
this.value = value;
}
}
public static void main(String[] args) {
// ์ ์ํ์ ๋ค๋ฃจ๋ ์ ๋ค๋ฆญ ํด๋์ค
Sample<Integer> s1 = new Sample<>();
s1.setValue(1);
// ์ค์ํ์ ๋ค๋ฃจ๋ ์ ๋ค๋ฆญ ํด๋์ค
Sample<Double> s2 = new Sample<>();
s2.setValue(1.0);
// ๋ฌธ์์ด์ ๋ค๋ฃจ๋ ์ ๋ค๋ฆญ ํด๋์ค
Sample<String> s3 = new Sample<>();
s3.setValue("1");
}
์ ๋ค๋ฆญ ์ธํฐํ์ด์ค
์ธํฐํ์ด์ค์๋ ์ ๋ค๋ฆญ์ ์ ์ฉ ํ ์ ์๋ค. ๋จ, ์ธํฐํ์ด์ค๋ฅผ implements ํ ํด๋์ค์์๋ ์ค๋ฒ๋ผ์ด๋ฉํ ๋ฉ์๋๋ฅผ ์ ๋ค๋ฆญ ํ์
์ ๋ง์ถฐ์ ๋๊ฐ์ด ๊ตฌํํด ์ฃผ์ด์ผ ํ๋ค.
interface ISample<T> {
public void addElement(T t, int index);
public T getElement(int index);
}
class Sample<T> implements ISample<T> {
private T[] array;
public Sample() {
array = (T[]) new Object[10];
}
@Override
public void addElement(T element, int index) {
array[index] = element;
}
@Override
public T getElement(int index) {
return array[index];
}
}
public static void main(String[] args) {
Sample<String> sample = new Sample<>();
sample.addElement("This is string", 5);
sample.getElement(5);
}
์ ๋ค๋ฆญ ํจ์ํ ์ธํฐํ์ด์ค
ํนํ ์ ๋ค๋ฆญ ์ธํฐํ์ด์ค๊ฐ ์ ๋ง ๋ง์ด ์ฌ์ฉ๋๋ ๊ณณ์ด ๋ฐ๋ก ๋๋ค ํํ์์ ํจ์ํ ์ธํฐํ์ด์ค์ด๋ค. ์์ง ์๋ฐ์ ๋๋ค์์ ๋ํด ๋ฐฐ์ฐ์ง ์์ ๋ ์๋ถ๋ค๋ ๊ณ์๊ฒ ์ง๋ง, ์์ผ๋ก ๋ฐฐ์ธ ์์ ์ผ ๊ฒ์ด๋ ๋๋ค ํจ์์ ์ ๋ค๋ฆญ์ ์์ฉ ํํ๋ฅผ ๋์ ์ตํ๊ณ ๊ฐ๋๊ฒ์ ์ถ์ฒํ๋ ๋ฐ๋ค.
// ์ ๋ค๋ฆญ์ผ๋ก ํ์
์ ๋ฐ์, ํด๋น ํ์
์ ๋ ๊ฐ์ ๋ํ๋ ์ธํฐํ์ด์ค
interface IAdd<T> {
public T add(T x, T y);
}
public class Main {
public static void main(String[] args) {
// ์ ๋ค๋ฆญ์ ํตํด ๋๋ค ํจ์์ ํ์
์ ๊ฒฐ์
IAdd<Integer> o = (x, y) -> x + y; // ๋งค๊ฐ๋ณ์ x์ y ๊ทธ๋ฆฌ๊ณ ๋ฐํํ ํ์
์ด intํ์ผ๋ก ์ค์ ๋๋ค.
int result = o.add(10, 20);
System.out.println(result); // 30
}
}

์ ๋ค๋ฆญ ๋ฉ์๋
์ ๋ค๋ฆญ ๋ฉ์๋ ๋ถ๋ถ์ ์ ๋ค๋ฆญ ํด๋์ค, ์ธํฐํ์ด์ค์ ๋ฌ๋ฆฌ ๋์ด๋๊ฐ ์กฐ๊ธ ์๋ค.
์๋์ ๊ฐ์ด ์ ๋ค๋ฆญ ํด๋์ค์์ ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํ๋ ๋ฉ์๋๋ฅผ ์ ๋ค๋ฆญ ๋ฉ์๋๋ผ๊ณ ์ฐฉ๊ฐํ๊ธฐ ์ฌ์ด๋ฐ, ์ด๊ฒ์ ๊ทธ๋ฅ ํ์ ํ๋ผ๋ฏธํฐ๋ก ํ์ ์ ์ง์ ํ ๋ฉ์๋ ์ผ ๋ฟ์ด๋ค.
class FruitBox<T> {
public T addBox(T x, T y) {
// ...
}
}
์ ๋ค๋ฆญ ๋ฉ์๋๋, ๋ฉ์๋์ ์ ์ธ๋ถ์ <T> ๊ฐ ์ ์ธ๋ ๋ฉ์๋๋ฅผ ๋งํ๋ค.
์์์๋ ํด๋์ค์ ์ ๋ค๋ฆญ <T> ์์ ์ค์ ๋ ํ์
์ ๋ฐ์์ ๋ฐํ ํ์
์ผ๋ก ์ฌ์ฉํ ๋ฟ์ธ ์ผ๋ฐ ๋ฉ์๋๋ผ๋ฉด, ์ ๋ค๋ฆญ ๋ฉ์๋๋ ์ง์ ๋ฉ์๋์ <T> ์ ๋ค๋ฆญ์ ์ค์ ํจ์ผ๋ก์ ๋์ ์ผ๋ก ํ์
์ ๋ฐ์์ ์ฌ์ฉํ ์ ์๋ ๋
๋ฆฝ์ ์ผ๋ก ์ด์ฉ ๊ฐ๋ฅํ ์ ๋ค๋ฆญ ๋ฉ์๋๋ผ๊ณ ์ดํดํ๋ฉด ๋๋ค.
class FruitBox<T> {
// ํด๋์ค์ ํ์
ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์์ ์ฌ์ฉํ๋ ์ผ๋ฐ ๋ฉ์๋
public T addBox(T x, T y) {
// ...
}
// ๋
๋ฆฝ์ ์ผ๋ก ํ์
ํ ๋น ์ด์๋๋ ์ ๋ค๋ฆญ ๋ฉ์๋
public static <T> T addBoxStatic(T x, T y) {
// ...
}
}
์ฆ, ์ ๋ค๋ฆญ ํด๋์ค์ ์ ์๋ ํ์ ๋งค๊ฐ๋ณ์์ ์ ๋ค๋ฆญ ๋ฉ์๋์ ์ ์๋ ํ์ ๋งค๊ฐ๋ณ์๋ ๋ณ๊ฐ์ธ๊ฒ ๋๋ ๊ฒ์ด๋ค. ์ ๋ค๋ฆญ ๋ฉ์๋์ ์ ๋ค๋ฆญ ํ์ ์ ์ธ ์์น๋ ๋ฉ์๋ ๋ฐํ ํ์ ๋ฐ๋ก ์์ด๋ค.

์ ๋ค๋ฆญ ๋ฉ์๋ ํธ์ถ ์๋ฆฌ
๊ทธ๋ผ ์ ๋ค๋ฆญ ๋ฉ์๋๋ฅผ ํธ์ถ์ ์ด๋ป๊ฒ ํ ๊น?
์ ๋ค๋ฆญ ํ์ ์ ๋ฉ์๋๋ช ์์ ์ง์ ํด์คฌ์ผ๋, ํธ์ถ ์ญ์ ๋ฉ์๋ ์ผ์ชฝ์ ์ ๋ค๋ฆญ ํ์ ์ด ์์นํ๊ฒ ๋๋ค.
FruitBox.<Integer>addBoxStatic(1, 2);
FruitBox.<String>addBoxStatic("์๋
", "์๊ฐ");

์ด๋ ์ปดํ์ผ๋ฌ๊ฐ ์ ๋ค๋ฆญ ํ์ ์ ๋ค์ด๊ฐ ๋ฐ์ดํฐ ํ์ ์ ๋ฉ์๋์ ๋งค๊ฐ๋ณ์๋ฅผ ํตํด ์ถ์ ํ ์ ์๊ธฐ ๋๋ฌธ์, ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ ๋ค๋ฆญ ๋ฉ์๋์ ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์๋ตํ๊ณ ํธ์ถํ ์ ์๋ค.
// ๋ฉ์๋์ ์ ๋ค๋ฆญ ํ์
์๋ต
FruitBox.addBoxStatic(1, 2);
FruitBox.addBoxStatic("์๋
", "์๊ฐ");

๊ทธ๋ฐ๋ฐ ํ๊ฐ์ง ๊ถ๊ธํ ์ ์ด ์์ ๊ฒ์ด๋ค. ํด๋์ค ์์ ๋ถ์ด์๋ ์ ๋ค๋ฆญ๊ณผ ์ ๋ค๋ฆญ ๋ฉ์๋๋ ๋๊ฐ์ <T> ์ธ๋ฐ ์ด๋ป๊ฒ ์ ๋ค๋ฆญ ๋ฉ์๋๋ง์ด ๋
๋ฆฝ์ ์ผ๋ก ์ด์ฉ๋๋์ง ๋ง์ด๋ค.
์ฌ์ค์ ์ฒ์ ์ ๋ค๋ฆญ ํด๋์ค๋ฅผ ์ธ์คํด์คํํ๋ฉด, ํด๋์ค ํ์ ๋งค๊ฐ๋ณ์์ ์ ๋ฌํ ํ์ ์ ๋ฐ๋ผ ์ ๋ค๋ฆญ ๋ฉ์๋๋ ํ์ ์ด ์ ํด์ง๊ฒ ๋๋ค. ๊ทธ๋ฐ๋ฐ ๋ง์ผ ์ ๋ค๋ฆญ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ ์ง์ ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ค๋ฅด๊ฒ ์ง์ ํด์ฃผ๊ฑฐ๋, ๋ค๋ฅธ ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋งค๊ฐ๋ณ์์ ๋๊ธดํ๋ฉด ๋ ๋ฆฝ์ ์ธ ํ์ ์ ๊ฐ์ง ์ ๋ค๋ฆญ ๋ฉ์๋๋ก ์ด์ฉ๋๊ฒ ๋๋ค.
class FruitBox<T, U> {
// ๋
๋ฆฝ์ ์ผ๋ก์ด์๋๋ ์ ๋ค๋ฆญ ๋ฉ์๋
public <T, U> void printBox(T x, U y) {
// ํด๋น ๋งค๊ฐ๋ณ์์ ํ์
์ถ๋ ฅ
System.out.println(x.getClass().getSimpleName());
System.out.println(y.getClass().getSimpleName());
}
}
public static void main(String[] args) {
FruitBox<Integer, Long> box1 = new FruitBox<>();
// ์ธ์คํด์คํ์ ์ง์ ๋ ํ์
ํ๋ผ๋ฏธํฐ <Integer, Long>
box1.printBox(1, 1);
// ํ์ง๋ง ์ ๋ค๋ฆญ ๋ฉ์๋์ ๋ค๋ฅธ ํ์
ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ ํ๋ฉด ๋
๋ฆฝ์ ์ผ๋ก ์ด์ฉ ๋๋ค.
box1.<String, Double>printBox("hello", 5.55);
box1.printBox("hello", 5.55); // ์๋ต ๊ฐ๋ฅ
}


์ ๋ค๋ฆญ ํ์ ๋ฒ์ ํ์ ํ๊ธฐ
์ ๋ค๋ฆญ์ ํ์ ์ ์ง์ ํด์ค์ผ๋ก์ ํด๋์ค์ ํ์ ์ ์ปดํ์ผ ํ์์์ ์ ํ์ฌ ํ์ ์์ธ์ ๋ํ ์์ ์ฑ์ ํ๋ณดํ๋ ๊ฒ์ ์ข์ง๋ง ๋ฌธ์ ๋ ๋๋ฌด ์์ ๋กญ๋ค๋ ์ ์ด๋ค.
์๋ฅผ๋ค์ด ๋ค์ ๊ณ์ฐ๊ธฐ ํด๋์ค๊ฐ ์๋ค๊ณ ํ์. ์ ์, ์ค์ ๊ตฌ๋ถ์์ด ๋ชจ๋ ๋ฐ์ ์ ์๊ฒ ํ๊ธฐ์ํด ์ ๋ค๋ฆญ์ผ๋ก ํด๋์ค๋ฅผ ๋ง๋ค์ด์ฃผ์๋ค. ํ์ง๋ง ๋จ์ํ <T> ๋ก ์ง์ ํ๊ฒ ๋๋ฉด ์ซ์์ ๊ด๋ จ๋ ๋ํผ ํด๋์ค ๋ฟ๋ง ์๋๋ผ String์ด๋ ๋ค๋ฅธ ํด๋์ค๋ค๋ ๋์
์ด ๊ฐ๋ฅํ๋ค๋ ์ ์ด ๋ฌธ์ ์ด๋ค.
// ์ซ์๋ง ๋ฐ์ ๊ณ์ฐํ๋ ๊ณ์ฐ๊ธฐ ํด๋์ค ๋ชจ๋
class Calculator<T> {
void add(T a, T b) {}
void min(T a, T b) {}
void mul(T a, T b) {}
void div(T a, T b) {}
}
public class Main {
public static void main(String[] args) {
// ์ ๋ค๋ฆญ์ ์๋ฌด ํ์
์ด๋ ๋ชจ๋ ํ ๋น์ด ๊ฐ๋ฅ
Calculator<Number> cal1 = new Calculator<>();
Calculator<Object> cal2 = new Calculator<>();
Calculator<String> cal3 = new Calculator<>();
Calculator<Main> cal4 = new Calculator<>();
}
}
๊ฐ๋ฐ์์ ์๋๋ก๋ ๊ณ์ฐ๊ธฐ ํด๋์ค์ ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ๋ก Number ์๋ฃํ๋ง ๋ค์ด์ค๋๋ก ํ๊ณ ๋ฌธ์์ด์ด๋ ๋ ๋ค๋ฅธ ํด๋์ค ์๋ฃํ์ด ๋ค์ด์ค๋ฉด ์๋๊ฒ ํ๊ณ ์ถ๋ค๊ณ ํ๋ค. ๊ทธ๋์ ๋์จ ๊ฒ์ด ์ ํ๋ ํ์ ๋งค๊ฐ๋ณ์ (Bounded Type Parameter) ์ด๋ค.
ํ์ ํ์ ํค์๋ extends
๊ธฐ๋ณธ์ ์ธ ์ฉ๋ฒ์ <T extends [์ ํํ์
]> ์ด๋ค. ์ ๋ค๋ฆญ <T> ์ extends ํค์๋๋ฅผ ๋ถ์ฌ์ค์ผ๋ก์จ, <T extends Number> ์ ๋ค๋ฆญ์ Number ํด๋์ค์ ๊ทธ ํ์ ํ์
(Integer, Double)๋ค๋ง ๋ฐ๋๋ก ํ์
ํ๋ผ๋ฏธํฐ ๋ฒ์๋ฅผ ์ ํ ํ ๊ฒ์ด๋ค.
ํด๋์ค์ ์์ ํค์๋์ ์ ๋ค๋ฆญ์ ํ์ ํ์ ํค์๋๊ฐ ๋๋ค ๋๊ฐ์ด extends ๋ผ ํผ๋ํ ์์ง๊ฐ ๋ค๋ถ์ด ์๋ค. ๊บพ์ ๊ดํธ ์์ extends๊ฐ ์์ผ๋ฉด ์ด๊ฑด ์ ํ์ ์๋ฏธํ๋ฉฐ ๊ดํธ ๋ฐ๊นฅ์ ์์ผ๋ฉด ์์์ผ๋ก ๋ณด๋ฉด ๋๋ค.

์ธํฐํ์ด์ค ํ์ ํ์
extends ํค์๋ ๋ค์์ ์ฌ ํ์ ์ ์ผ๋ฐ ํด๋์ค, ์ถ์ ํด๋์ค, ์ธํฐํ์ด์ค ๋ชจ๋ ์ฌ ์ ์๋ค. ์ธํฐํ์ด์ค ๋ถ๋ถ์ ์ฝ๊ฐ ํ๊น๋ฆด์ ์๋๋ฐ, ํด๋์ค์ ์์ ๊ด๊ณ์ ๋ค๋ฆ์ด ์์ผ๋ ๊ทธ๋๋ก ๋น๋์ด ์ ์ฉํ๋ฉด ๋๋ค.
interface Readable {
}
// ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ํด๋์ค
public class Student implements Readable {
}
// ์ธํฐํ์ด์ค๋ฅผ Readable๋ฅผ ๊ตฌํํ ํด๋์ค๋ง ์ ๋ค๋ฆญ ๊ฐ๋ฅ
public class School <T extends Readable> {
}
public static void main(String[] args) {
// ํ์
ํ๋ผ๋ฏธํฐ์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ํด๋์ค๋ง์ด ์ฌ์ ์๊ฒ ๋จ
School<Student> a = new School<Student>();
}
๋ค์ค ํ์ ํ์
๋ง์ผ 2๊ฐ ์ด์์ ํ์
์ ๋์์ ์์(๊ตฌํ)ํ ๊ฒฝ์ฐ๋ก ํ์
์ ํํ๊ณ ์ถ๋ค๋ฉด, & ์ฐ์ฐ์๋ฅผ ์ด์ฉํ๋ฉด ๋๋ค. ํด๋น ์ธํฐํ์ด์ค๋ค์ ๋์์ ๊ตฌํํ ํด๋์ค๊ฐ ์ ๋ค๋ฆญ ํ์
์ ๋์์ด ๋๊ฒ ๋๋ค.
๋จ, ์๋ฐ์์๋ ๋ค์ค ์์์ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์ ํด๋์ค๋ก๋ ๋ค์ค extends๋ ๋ถ๊ฐ๋ฅํ๊ณ ์ค๋ก์ง ์ธํฐํ์ด์ค๋ก๋ง์ด ๊ฐ๋ฅํ๋ค.
interface Readable {}
interface Closeable {}
class BoxType implements Readable, Closeable {}
class Box<T extends Readable & Closeable> {
List<T> list = new ArrayList<>();
public void add(T item) {
list.add(item);
}
}
public static void main(String[] args) {
// Readable ์ Closeable ๋ฅผ ๋์์ ๊ตฌํํ ํด๋์ค๋ง์ด ํ์
ํ ๋น์ด ๊ฐ๋ฅํ๋ค
Box<BoxType> box = new Box<>();
// ์ฌ์ง์ด ์ต์์ Object ํด๋์ค์ฌ๋ ํ ๋น ๋ถ๊ฐ๋ฅํ๋ค
Box<Object> box2 = new Box<>(); // ! Error
}
์ ๋ค๋ฆญ์ด ์ฌ๋ฌ๊ฐ์ธ ๋ค์ค ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ์๋ ๊ฐ๊ฐ ๋ค์ค ์ ํ์ ๊ฑฐ๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ค. (๊ฐ๋ ์ฑ์ด ์ผ์ ์ด ๋๋๊ฑด ํจ์ )
interface Readable {}
interface Closeable {}
interface Appendable {}
interface Flushable {}
class School<T extends Readable & Closeable, U extends Appendable & Closeable & Flushable>
void func(T reader, U writer){
}
}
์ฌ๊ท์ ํ์ ํ์
์ฌ๊ท์ ํ์ ํ์ ์ด๋ ์๊ธฐ ์์ ์ด ๋ค์ด๊ฐ ํํ์์ ์ฌ์ฉํ์ฌ ํ์ ๋งค๊ฐ๋ณ์์ ํ์ฉ ๋ฒ์๋ฅผ ํ์ ์ํค๋ ๊ฒ์ ๋งํ๋ค. ์ค๋ฌด์์ ์ฃผ๋ก Comparable ์ธํฐํ์ด์ค์ ํจ๊ป ์ฐ์ธ๋ค.
์๋ฅผ๋ค์ด ๋ค์๊ณผ ๊ฐ์ด <E extends Comparable<E>> ์ ๋ค๋ฆญ E์ ํ์
๋ฒ์๋ฅผ Comparable<E> ๋ก ํ์ ํ๋ค๋ E๋ฅผ ์ค์ฒฉ์ํจ ํํ์์ ์ฌ์ฉํ ์ ์๋๋ฐ, ์ด ๋ง์ 'ํ์
E๋ ์๊ธฐ ์์ ์ ์๋ธ ํ์
์ผ๋ก ๊ตฌํํ Comparable ๊ตฌํ์ฒด๋ก ํ์ ' ํ๋ค๋ ๋ป์ด๋ค.
Comparable๋ ๊ฐ์ฒด๋ผ๋ฆฌ ๋น๊ต๋ฅผ ํด์ผ ํ ๋ compareTo() ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ ๋ ๊ตฌํํ๋ ์ธํฐํ์ด์ค์ด๋ค.
์๋ฐ์์ Integer, Double, String ๋ฑ์ด ๊ฐ ๋น๊ต๊ฐ ๋๋ ์ด์ ๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก Comparable๋ฅผ ๊ตฌํํ๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ฆ, Integer ๊ฐ์ฒด๋ฅผ ์ ๋ค๋ฆญ ํ์ E์ ํ ๋นํ๊ฒ ๋๋ค๋ฉด, Comparable์ ๊ตฌํํ ๊ฐ์ฒด๋ฉด์ ์ค๋ก์ง ๊ฐ์ E์ธ Integer ํ์ ๋ง ๋ฐ๋๋ค๋ ์๋ฏธ๊ฐ ๋๋ค. (์๊ธฐ ์์ ๋ง ๋ฐ๋ ๋ค๋ ํํ์ ์ด๋ ต๊ฒ ๋น๋๋ ค ํํํ ๊ฒ์ด๋ค)
๋ค์์ ์ปฌ๋ ์ ์ ์ธ์๋ก ๋ฐ์ ์ปฌ๋ ์ ์ ์์๋ค์ ์ต๋๊ฐ(max)๋ฅผ ๊ตฌํด ๋ฐํํ๋ ๋ฉ์๋ ์์ ์ด๋ค. ์ ๋ค๋ฆญ ๋ฉ์๋ ํ์ ์ผ๋ก ์ฌ๊ท์ ํ์ ํ์ ์ด ์ฌ์ฉ๋์๋ค.
class Compare {
// ์ธ๋ถ๋ก ๋ค์ด์จ ํ์
E๋ Comparable<E>๋ฅผ ๊ตฌํํ E ๊ฐ์ฒด ์ด์ด์ผ ํ๋ค.
public static <E extends Comparable<E>> E max(Collection<E> collection) {
if(collection.isEmpty()) throw new IllegalArgumentException("์ปฌ๋ ์
์ด ๋น์ด ์์ต๋๋ค.");
E result = null;
for(E e: collection) {
if(result == null) {
result = e;
continue;
}
if(e.compareTo(result) > 0) {
result = e;
}
}
return result;
}
}
public static void main(String[] args) {
Collection<Integer> list = Arrays.asList(56, 34, 12, 31, 65, 77, 91, 88);
System.out.println(Compare.max(list)); // 91
Collection<Number> list2 = Arrays.asList(56, 34, 12, 31, 65, 77, 91, 88);
System.out.println(Compare.max(list2)); // ! Error - Number ์ถ์ ๋ฉ์๋๋ Comparable๋ฅผ ๊ตฌํํ์ง์์๊ธฐ ๋๋ฌธ์ ๋ถ๊ฐ๋ฅ
}
์ ๋ค๋ฆญ ํ๋ณํ
์ ๋ค๋ฆญ ์บ์คํ ๋ฌธ์
๋ฐฐ์ด๊ณผ ๊ฐ์ ์ผ๋ฐ์ ์ธ ๋ณ์ ํ์ ๊ณผ ๋ฌ๋ฆฌ ์ง๋ค๋ฆญ ์๋ธ ํ์ ๊ฐ์๋ ํ๋ณํ์ด ๋ถ๊ฐ๋ฅํ๋ค. ์ฌ์ง์ด ๋์ ๋ ํ์ ์ด Object์ผ์ง๋ผ๋ ๋ง์ด๋ค. ์์ฐ์ค๋ฝ๊ฒ ๋คํ์ฑ์ด ์ ์ฉ๋ ๊ฒ์ด๋ผ ์๊ฐํ์์ง๋ง, ์ค์ ์ ๋ค๋ฆญ์ ์ ๋ฌ๋ฐ์ ๋ฑ ๊ทธ ํ์ ์ผ๋ก๋ง ์๋ก ์บ์คํ ์ด ๊ฐ๋ฅํ ๊ฒ์ด๋ค.
์ฒ์์ ์๊ฐํ ํ์ ํ๋ผ๋ฏธํฐ์ ๋คํ์ฑ์ ํฌํจ ์์๋ก์ ๊ฐ๋ฅํ๋ค๋๊ฑฐ์ง, ํ๋ณํ์ ๊ฐ์ฒด ๋ ๊ฐ์ฒด๋ฅผ ๋งํ๋ ๊ฑฐ๋ ๋ค๋ฅธ ๊ฐ๋ ์ด๋ค.
// ๋ฐฐ์ด์ OK
Object[] arr = new Integer[1];
// ์ ๋ค๋ฆญ์ ERROR
List<Object> list = new ArrayList<Integer>();
List<Object> listObj = null;
List<String> listStr = null;
// ์๋ฌ. List<String> -> List<Object>
listObj = (List<String>) listStr;
// ์๋ฌ. List<Object> -> List<String>
listStr = (List<Object>) listObj;
์ด ํน์ง์ด ์ ๋ฌธ์ ์๊ฐ ๋๋๋ฉด์ ์ ๋ค๋ฆญ ๊ฐ์ฒด์ ์์๋ฅผ ๋ฃ๊ฑฐ๋ ๊ฐ์ ธ์ฌ๋, ์บ์คํ ๋ฌธ์ ๋ก ์ธํด ์ ๋ก์ฌํญ์ด ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
์๋ฅผ ๋ค์ด ๋ฐฐ์ด ๊ฐ์ ๊ฒฝ์ฐ ๋ฐ๋ณต๋ฌธ์ ๋ณ์๋ก Object ํ์ ์ผ๋ก ๋ฐ์ ์ฌ์ฉํด๋ ๋ฌธ์ ๊ฐ ์๋ค.
public static void main(String[] args) {
Apple[] integers = new Apple[]{
new Apple(),
new Apple(),
new Apple(),
};
print(integers);
}
public static void print(Fruit[] arr) {
for (Object e : arr) {
System.out.println(e);
}
}
ํ์ง๋ง ์์ ์ฝ๋์์ ๋ฐฐ์ด์ ๋ฆฌ์คํธ์ ์ ๋ค๋ฆญ์ผ๋ก ๋ฐ๊พธ๋ฉด ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
public static void main(String[] args) {
List<Integer> lists = new ArrayList<>(Arrays.asList(1, 2, 3));
print(lists); // ! ์ปดํ์ผ ์๋ฌ ๋ฐ์
}
public static void print(List<Object> list) {
for (Object e : list) {
System.out.println(e);
}
}
๋ฐฐ์ด ๊ฐ์ ๊ฒฝ์ฐ print ๋ฉ์๋์ ๋งค๊ฐ๋ณ์๋ก ์๊ท๋จผํธ๊ฐ ๋์ด๊ฐ๋ Integer[] ๋ฐฐ์ด ํ์
์ด Object[] ๋ฐฐ์ด ํ์
์ผ๋ก ์
์บ์คํ
์ด ์ ์ฉ๋์ด ๋ฌธ์ ๊ฐ ์์ง๋ง, ์ ๋ค๋ฆญ ๊ฐ์ ๊ฒฝ์ฐ ํ์
ํ๋ผ๋ฏธํฐ๊ฐ ์ค๋ก์ง ๋๊ฐ์ ํ์
๋ง ๋ฐ๊ธฐ ๋๋ฌธ์ ๋คํ์ฑ์ ์ด์ฉํ ์ ์์ด์ ๊ทธ๋ฐ ๊ฒ์ด๋ค.
์ ๋ค๋ฆญ ์์ผ๋ ์นด๋
๋ฐ๋ผ์ ์ ๋ค๋ฆญ ๊ฐ์ ํ๋ณํ์ ์ฑ๋ฆฝ๋๊ฒ ํ๊ธฐ ์ํด์๋ ์ ๋ค๋ฆญ์์ ์ ๊ณตํ๋ ์์ผ๋ ์นด๋ ? ๋ฌธ๋ฒ์ ์ด์ฉํ์ฌ์ผ ํ๋ค.
<?>: Unbounded Wildcards (์ ํ ์์)- ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋์นํ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ์ผ๋ก ๋ชจ๋ ํด๋์ค๋ ์ธํฐํ์ด์ค ํ์ ์ด ์ฌ ์ ์๋ค
<? extends ์์ํ์ >: Upper Bounded Wildcards (์์ ํด๋์ค ์ ํ)- ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋์นํ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ์ผ๋ก ์์ ํ์ ์ด๋ ์์ ํ์ ์ ํ์ ํ์ ๋ง ์ฌ ์ ์๋ค
<? super ํ์ํ์ >: Lower Bounded Wildcards (ํ์ ํด๋์ค ์ ํ)- ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋์นํ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ์ผ๋ก ํ์ ํ์ ์ด๋ ํ์ ํ์ ์ ์์ ํ์ ๋ง ์ฌ ์ ์๋ค
List<? extends Object> list = new ArrayList<String>();
List<? super String> list2 = new ArrayList<Object>();
public static void main(String[] args) {
List<Integer> lists = new ArrayList<>(Arrays.asList(1, 2, 3));
print(lists); // OK
}
// Number์ ๊ทธ ํ์ ํ์
(Integer, Double ๋ฑ) ๋ง์ ๋ฐ๋๋ค
public static void print(List<? extends Number> list) {
for (Object e : list) {
System.out.println(e);
}
}
์ ๋ค๋ฆญ ์์ผ๋ ์นด๋ ๋ฌธ๋ฒ์ ์๋ฐ์ ์ ๋ค๋ฆญ์์ ๊ฐ์ฅ ๋์ด๋๊ฐ ๋์ ๋ถ๋ถ์ด๋ค. ์ธ์ <? extends ์์ํ์
> ๋ฅผ ์จ์ผ๋๊ณ ์ธ์ <? super ํ์ํ์
> ์จ์ผํ๋์ง๋ ํ์
๊ฐ๋ฐ์๋ ๋๋๋ก ์ด๋ ค์ ํ๋ ๋ถ๋ถ์ด๋ค. ๋ฐ๋ผ์ ๋ณ๋์ ์๋ ํฌ์คํ
์ ํตํด ์ ๋ค๋ฆญ ์์ผ๋์นด๋ ์ฌ์ฉ๋ฒ์ ์๋ฒฝํ ์ดํดํด๋ณด๋๋ก ํ์.
[JAVA] โ ์ ๋ค๋ฆญ - ๊ณต๋ณ์ฑ & ์์ผ๋์นด๋ ์๋ฒฝ ์ดํดํ๊ธฐ
์๋ฐ์ ๊ณต๋ณ์ฑ / ๋ฐ๊ณต๋ณ์ฑ ์ ๋ค๋ฆญ์ ์์ผ๋์นด๋๋ฅผ ๋ฐฐ์ฐ๊ธฐ ์์ ์ ์ ์ง์์ผ๋ก ์๊ณ ๋์ด๊ฐ์ผํ ๊ฐ๋ ์ด ์๋ค. ์กฐ๊ธ ๋์ด๋ ์๋ ํ๋ก๊ทธ๋๋ฐ ๋ถ๋ถ์ ํ์ต ํ๋ค๋ณด๋ฉด ํ๋ฒ์ฏค์ ๋ค์ด๋ณผ์ ์๋ ๊ณต๋ณ
inpa.tistory.com
์ ๋ค๋ฆญ ํ์ ์๊ฑฐ
์ ๋ค๋ฆญ์ ํ์ ์์ ์ฑ์ ์ํด JDK 1.5๋ถํฐ ๋์ ๋ ๋ฌธ๋ฒ์ผ๋ก ์ด์ ์๋ฐ์์๋ ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ ์์ด ์๋ฐ ์ธ์ด๋ฅผ ์ฝ๋ฉํด์๋ค. ๊ทธ๋์ ์ด์ ์ ์๋ฐ ๋ฒ์ ์ ์ฝ๋์ ํธํ์ฑ์ ์ํด ์ ๋ค๋ฆญ ์ฝ๋๋ ์ปดํ์ผ๋๋ฉด ์ ๋ค๋ฆญ ํ์ ์ ์ฌ๋ผ์ง๊ฒ ๋๋ค. ์ฆ, ํด๋์ค ํ์ผ(.class)์๋ ์ ๋ค๋ฆญ ํ์ ์ ๋ํ ์ ๋ณด๋ ์กด์ฌํ์ง ์๋ ๊ฒ์ด๋ค.
์ด์ฐ๋ณด๋ฉด ์ ๋ค๋ฆญ์ ์ค์ ๋ฐ์ดํธ ์ฝ๋์๋ ์๋ ๋ฐ์ชฝ์ง๋ฆฌ ์ธ์ด ๋ฌธ๋ฒ์ด๋ผ๊ณ ํ ์ ์๋ค. ๊ทธ๋์ ์ ๋ค๋ฆญ์ ๊ฐ๋ฐ์๊ฐ ์๋ชป๋ ๋ฐฉํฅ์ผ๋ก ์ค๊ณ๋ฅผ ํ๋ฉด ์ ์ฌ์ ์ธ ํ ์ค์ผ(heap pollution) ๋ฌธ์ ์ ๋น ์ง๊ฒ ๋ ์ ์๋ค. ๋ฐ๋ผ์ ์ฐ๋ฆฌ๊ฐ ๋ฐ์ดํธ ์ฝ๋๋ฅผ ๋ณด๊ณ ์ฝ๋ฉํ ๊ฒ์ ์๋์ง๋ง, ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ค๋ฆญ์ ์ค๊ณํ๊ธฐ ์ํด์ ์ ๋ค๋ฆญ์ ์ปดํ์ผ ๊ณผ์ ์ ํ๋ฒ ์ฏค ์์๋ ํ์์ฑ์ด ์๋ค.
[JAVA] โ ์ ๋ค๋ฆญ ํ์ ์๊ฑฐ ์ปดํ์ผ ๊ณผ์ ์์๋ณด๊ธฐ
์ ๋ค๋ฆญ ํ์ ์๊ฑฐ (Erasure) ์ ๋ค๋ฆญ์ ํ์ ์์ ์ฑ์ ๋ณด์ฅํ๋ฉฐ, ์คํ์๊ฐ์ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ์ง ์๋๋ก ํ๊ธฐ์ํด JDK 1.5๋ถํฐ ๋์ ๋ ๋ฌธ๋ฒ์ผ๋ก, ์ด์ ์๋ฐ์์๋ ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ ์์ด ์๋ฐ๋ฅผ
inpa.tistory.com
# ์ฐธ๊ณ ์๋ฃ
https://www.youtube.com/watch?v=Vv0PGUxOzq0
https://www.youtube.com/watch?v=w5AKXDBW1gQ
์ด ๊ธ์ด ์ข์ผ์ จ๋ค๋ฉด ๊ตฌ๋ & ์ข์์
์ฌ๋ฌ๋ถ์ ๊ตฌ๋
๊ณผ ์ข์์๋
์ ์์๊ฒ ํฐ ํ์ด ๋ฉ๋๋ค.