GiantStepDEV

Generics λž€?

βœ… μžλ°” 8 μ—μ„œ 좔가됨

  • 데이터 νƒ€μž…(data type)을 μΌλ°˜ν™”ν•œλ‹€(Generalize)λŠ” 것을 의미
    == 데이터 ν˜•μ‹μ— μ˜μ‘΄ν•˜μ§€ μ•Šκ³ , ν•˜λ‚˜μ˜ 값이 μ—¬λŸ¬ λ‹€λ₯Έ 데이터 νƒ€μž…μ„ κ°€μ§ˆ 수 μžˆλ„λ‘ ν•˜λŠ” 방법

ν”„λ‘œκ·Έλž¨μ—μ„œ λ³€μˆ˜λ₯Ό μ„ μ–Έν•  λ•Œ λͺ¨λ“  λ³€μˆ˜λŠ” μžλ£Œν˜•μ„ κ°€μ§€κ³  있음.

(int, double, char ...)

뿐만 μ•„λ‹ˆλΌ λ©”μ†Œλ“œμ—μ„œ λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” κ²½μš°μ—λ„ μžλ£Œν˜•μ„ κ°€μ§€κ³  있음.

public void add(int a, int b){}

이처럼 일반적인 κ²½μš°μ—λŠ” ν•˜λ‚˜μ˜ μžλ£Œν˜•μœΌλ‘œ κ΅¬ν˜„ν•˜μ§€λ§Œ, λ³€μˆ˜λ‚˜ λ©”μ†Œλ“œμ˜ μžλ£Œν˜•μ„ ν•„μš”μ— 따라 μ—¬λŸ¬ μžλ£Œν˜•μœΌλ‘œ λ°”κΏ€ 수 μžˆλ‹€λ©΄ ν”„λ‘œκ·Έλž¨μ€ 훨씬! μœ μ—°ν•΄μ§„λ‹€.

이와 같이 μ–΄λ–€ 값이 μ°Έμ‘°ν•˜λŠ” μžλ£Œν˜•μ΄ μ•„λ‹Œ μ—¬λŸ¬ μ°Έμ‘°ν˜•μ„ μ‚¬μš©ν•  수 μžˆλ„λ‘ ν”„λ‘œκ·Έλž˜λ° ν•˜λŠ” 것을 "μ œλ„€λ¦­ ν”„λ‘œκ·Έλž˜λ°' 이라고 함.

 

μ œλ„€λ¦­μ€ ν΄λž˜μŠ€λ‚˜ λ©”μ†Œλ“œμ—μ„œ μ‚¬μš©ν•  λ‚΄λΆ€ 데이터 νƒ€μž…μ„ 컴파일 μ‹œμ— 미리 μ§€μ •ν•˜λŠ” 방법을 μ‚¬μš©!!!

μ΄λ ‡κ²Œ 컴파일 μ‹œ 검사λ₯Ό μˆ˜ν–‰ν•˜λ©΄ μ•„λž˜μ™€ 같은 μž₯점을 가짐.

  • 컴파일 μ‹œ κ°•ν•œ νƒ€μž… 체크
  • νƒ€μž… λ³€ν™˜ 제거

μžλ°” 8 이전 μŠ€νƒ€μΌ

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("μ•ˆλ…•ν•˜μ„Έμš”.");
        list.add(0); // 였λ₯˜ μ•ˆλ‚¨.
        String str = (String) list.get(1);
    }
}
  • String str = (String) list.get(1);
    λ™μž‘ν•˜λ©΄ μ•ˆλ˜λŠ”λ° 컴파일이 였λ₯˜λ₯Ό λͺ» μž‘μ•„λƒ„. μ§€κΈˆμ²˜λŸΌ κ°„λ‹¨ν•œ 예제 μ½”λ“œλ₯Ό μ§€ λ•ŒλŠ” μ‚¬λžŒμ΄ 금방 μž‘μ•„λ‚Ό 수 μžˆμ§€λ§Œ μΆ”ν›„ ν˜„μ—…μ—μ„œ 이런 μ‹μœΌλ‘œ μ½”λ“œ μž‘μ„± ν›„ λ°°ν¬ν•˜λ©΄ 일이 컀질 수 있음.

🚨였λ₯˜ λ°œμƒ

Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
	at μ œλ„€λ¦­μΌλ°˜0127.Main.main(Main.java:12)

Generic νƒ€μž…

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("java!");
        String str = list.get(0); // νƒ€μž… λ³€ν™˜ 제거, 0번째 값을 μ½μ–΄μ˜΄.
        System.out.println(str);
    }
}
hello
  • String μ΄μ™Έμ—λŠ” μ•ˆλ°›κ² λ‹€κ³  μ²˜μŒμ— 데이터 νƒ€μž… μ§€μ •!(= κ°•ν•œ νƒ€μž… 체크)
  • μ •λ¦¬ν•˜λ©΄.. Listμ—μ„œ μ‚¬μš©ν•  데이터 νƒ€μž…μ„ 미리 μ§€μ •ν•¨μœΌλ‘œμ¨ 컴파일 μ‹œ νƒ€μž…μ²΄ν¬κ°€ μΌμ–΄λ‚˜λ„λ‘ 함.
  • λ”°λΌμ„œ, νƒ€μž… λ³€ν™˜λ„ μ•ˆν•΄λ„ 됨.

Generic λ©”μ†Œλ“œ

  • νƒ€μž… λ³€μˆ˜λ₯Ό μ‚¬μš©ν•΄ λ‹€ν˜•μ„± κ΅¬ν˜„(?)
  • μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬μ—μ„œ μ€‘μš”ν•˜κΈ° μ“°μ΄λŠ” 문법이기도 함.
  • νƒ€μž… λ³€μˆ˜λŠ” 클래슀 뿐만 μ•„λ‹ˆλΌ λ©”μ†Œλ“œμ˜ λ§€κ°œλ³€μˆ˜λ‚˜ λ°˜ν™˜νƒ€μž…μœΌλ‘œλ„ μ‚¬μš© κ°€λŠ₯
class Person <T> {
    public T info;

    Person(T info) {
        this.info = info;
    }
}
T λ₯Ό νƒ€μž… λ³€μˆ˜(type variable)라고 ν•˜λ©°, μž„μ˜μ˜ μ°Έμ‘°ν˜• νƒ€μž…μ„ μ˜λ―Έν•¨.
TλŠ” λ³€μˆ˜λͺ…을 μ˜λ―Έν•˜λ©° λ‹€λ₯Έ 문자둜 해도 됨..ν—ˆλ‚˜ 일반적으둜 λŒ€λ¬Έμž T둜 씀.
public class Main {
    public static void main(String[] args) {
        Person<String> p1 = new Person<>("양콩미");
        System.out.println(p1.info);
        
        Person<Integer> p2 = new Person<>(30);
        System.out.println(p2.info);
    }
}
  • νƒ€μž… λ³€μˆ˜λŠ” λ©”μ†Œλ“œμ˜ λ§€κ°œλ³€μˆ˜λ‚˜ λ°˜ν™˜κ°’μœΌλ‘œλ„ μ‚¬μš© κ°€λŠ₯
  • μœ„μ™€ 같이 μ„ μ–Έλœ μ œλ„€λ¦­ 클래슀λ₯Ό 생성할 λ•Œμ—λŠ” νƒ€μž… λ³€μˆ˜ μžλ¦¬μ— μ‚¬μš©ν•  μ‹€μ œ νƒ€μž… λͺ…μ‹œν•˜λ©΄ 됨.
양콩미
30

Generic λ©€ν‹° νƒ€μž…

class Product<T, M> {
    private T name;
    private M year;

    public Product(T name, M year) {
        this.name = name;
        this.year = year;
    }

    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }

    public M getYear() {
        return year;
    }

    public void setYear(M year) {
        this.year = year;
    }
}
public class MultiTypeEx {
    public static void main(String[] args) {
        Product<String, Integer> laptop = new Product<>("λ§₯뢁에어", 2022);
        System.out.println(laptop.getName());
        Product<Integer, String> tv = new Product<>(2020, "λ§₯λΆν”„λ‘œ");
        System.out.println(tv.getYear());
    }
}

Generic μ‘μš© 예제

public class Powder {
	public void doPrinting() {
        System.out.println("Powder 재료둜 좜λ ₯ν•©λ‹ˆλ‹€.");
    }
    @Override
    public String toString() {
    	return "μž¬λ‘œλŠ” Powder μž…λ‹ˆλ‹€.";
    }
}
  • @Override λŠ” Object 클래슀
    μ˜€λ²„λΌμ΄λ”© μ•ˆν•˜λ©΄ getMaterial() ν˜ΈμΆœμ‹œ ν•΄λ‹Ή 객체의 ν•΄μ‹œμ½”λ“œκ°€ λ°˜ν™˜λ˜κΈ° λ•Œλ¬Έμ— μ•Œμ•„λ³΄κΈ° νž˜λ“€μ–΄μ„œ μ‚¬μš©.
public class Plastic {
	public void doPrinting() {
        System.out.println("Plastic 재료둜 좜λ ₯ν•©λ‹ˆλ‹€.");
    }
    @Override
    public String toString() {
    	return "μž¬λ‘œλŠ” Plastic μž…λ‹ˆλ‹€.";
    }
}
public class GenericPrinter<T> {
	private T material;
    
    public void setMaterial(T material) {
    	this.material = material;
    }
    
    public T getMaterial() {
    	return material;
    }
    
    @Override
    public String toString() {
    	return material.toString();
    }
}
public class Main {
	public static void main(String[] args) {
    	GenericPrinter<Powder> powderPrinter = new GenericPrinter<>();
        powderPrinter.setMaterial(new Powder());
        Powder powder = powderPrinter.getMaterial();
        System.out.println(powder);
        
        GenericPrinter<Plastic> plasticPrinter = new GenericPrinter<>();
        plasticPrinter.setMaterial(new Plastic());
        Plastic plastic = plasticPrinter.getMaterial();
        System.out.println(plastic);
    }
}
  • Powder νƒ€μž…μ˜ 객체λ₯Ό μƒμ„±ν•˜μ—¬ setMaterial() 의 λ§€κ°œλ³€μˆ˜λ‘œ 전달
μž¬λ£ŒλŠ” νŒŒμš°λ” μž…λ‹ˆλ‹€.

🐸 : μœ„ 예제 처럼 T νƒ€μž…μ—λŠ” μ•„λ¬΄κ±°λ‚˜ 듀어와도 상관없어. ν•˜μ§€λ§Œ μ΄λ ‡κ²Œ μ œν•œμ΄ 없을 경우, μ‹€μ œ λ™μž‘κ³Ό κ΄€λ ¨ μ—†λŠ” νƒ€μž… λ³€μˆ˜λ„ λ‹€ λ“€μ–΄κ°ˆ 수 있기 λ•Œλ¬Έμ— λ¬Έμ œκ°€ 될 수 μžˆμ–΄. 이런 이유둜 λ“€μ–΄κ°ˆ 수 μžˆλŠ” 것을 μ œν•œλ‘λŠ” 것도 κ°€λŠ₯ν•΄.

🐢 : μ–΄λ–»κ²Œ?

🐸 : 상속을 μ΄μš©ν•˜λ©΄ 돼! 상속 λ°›μ§€ μ•Šμ€ ν΄λž˜μŠ€λŠ” 생성할 수 없도둝 μ œν•œμ„ κ±°λŠ”κ±°μ•Ό.

public abstract class Material {
    public abstract void doPrinting();
}
public class Powder extends Material {
    @Override
    public void doPrinting() {
        System.out.println("Powder 재료둜 좜λ ₯ν•©λ‹ˆλ‹€.");
    }

    @Override
    public String toString() {
        return "μž¬λ£ŒλŠ” νŒŒμš°λ” μž…λ‹ˆλ‹€.";
    }
}
public class Plastic extends Material {
    @Override
    public void doPrinting() {
        System.out.println("Plastic 재료둜 좜λ ₯ν•©λ‹ˆλ‹€.");
    }
    @Override
    public String toString() {
        return "μž¬λ£ŒλŠ” Plastic μž…λ‹ˆλ‹€.";
    }
}
public class Water {
    public void doPrinting() {
        System.out.println("Water 재료둜 좜λ ₯ν•©λ‹ˆλ‹€.");
    }
   
    @Override
    public String toString() {
        return "μž¬λ£ŒλŠ” Water μž…λ‹ˆλ‹€.";
    }
}
  • Water ν΄λž˜μŠ€λŠ” Material 상속 μ•ˆ 함
public class GenericPrinter<T extends Material> {
    private T material;

    public void setMaterial(T material) {
        this.material = material;
    }
    public T getMaterial() {
        return material;
    }
    @Override
    public String toString() {
        return material.toString();
    }
}
  • Materialλ₯Ό 상속받은 클래슀만 νƒ€μž… λ³€μˆ˜λ‘œ μ§€μ • κ°€λŠ₯ν•˜λ„λ‘ μ œν•œ!

Main

GenericPrinter<Water> waterPrinter = new GenericPrinter<>();
java: type argument μ œλ„€λ¦­μ‘μš©0130.Water is not within bounds of type-variable T
였λ₯˜!!
νƒ€μž… λ³€μˆ˜λ₯Ό Material μžμ‹ 클래슀만 λ“€μ–΄μ˜¬ 수 μžˆλ„λ‘ μ œν•œν–ˆκΈ° λ•Œλ¬Έμ— WaterλŠ” μ§€μ • λΆˆκ°€
μ‚¬μš©ν•˜λ €λ©΄ Water extends Material ν•΄μ£Όλ©΄ 됨.
ν•˜μ§€λ§Œ! μ‹€μ œλ‘œ 클래슀 섀계할 λ•ŒλŠ” λ§€κ°œλ³€μˆ˜ λ‹€ν˜•μ„±μœΌλ‘œ μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŒ.
ν•΄λ‹Ή μ˜ˆμ œλŠ” μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬ μžλ£Œκ΅¬μ‘°κ°€ 이런 μ‹μœΌλ‘œ μ‚¬μš©λ˜κ³  μžˆμŒμ„ μ΄ν•΄ν•˜κΈ° μœ„ν•΄ ν•΄λ³Έ κ²ƒμž„μ„ μΈμ§€ν•˜μž.
profile

GiantStepDEV

@kongmi

ν¬μŠ€νŒ…μ΄ μ’‹μ•˜λ‹€λ©΄ "μ’‹μ•„μš”β€οΈ" λ˜λŠ” "κ΅¬λ…πŸ‘πŸ»" ν•΄μ£Όμ„Έμš”!