ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] Java Generic(μ œλ„€λ¦­)
    Android/Java 2021. 3. 1. 15:43
    λ°˜μ‘ν˜•
    • 이 글은 "μžλ°” 온라인 μŠ€ν„°λ””"μ—μ„œ κ³΅λΆ€ν•œ λ‚΄μš©μ„ μž‘μ„±ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

    Genericμ΄λž€?

    • Integerν˜• λ°°μ—΄, Stringν˜• λ°°μ—΄ λ“±λ“± 배열에 ν¬ν•¨λ˜λŠ” μ›μ†Œμ˜ νƒ€μž…λ§ˆλ‹€ μΆ”κ°€, μ‚­μ œ, μ •λ ¬κ³Ό 같은 ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜κ³  μ‚¬μš©ν•˜λŠ” 것은 λΆ„λͺ… λΉ„νš¨μœ¨μ μΌ κ²ƒμž…λ‹ˆλ‹€.

    • μžλ°”μ˜ Generic은 λ°μ΄ν„°μ˜ νƒ€μž…μ„ μΌλ°˜ν™”ν•œλ‹€λŠ” 의미둜 ν΄λž˜μŠ€λ‚˜ λ©”μ†Œλ“œ μ •μ˜ μ‹œ μΌλ°˜ν™”ν•˜μ—¬ μ‚¬μš©ν•  데이터 νƒ€μž…μ„ 컴파일 μ‹œμ— 미리 μ§€μ •ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.

    • JDK1.5 λΆ€ν„° Generic을 μ‚¬μš©κ°€λŠ₯ν•˜λ©°, 컴파일 μ‹œ νƒ€μž…μ΄ 정해지기 λ•Œλ¬Έμ—, ν΄λž˜μŠ€λ‚˜ λ©”μ†Œλ“œ 내뢀에 μ‚¬μš©λ  λ°μ΄ν„°μ˜ νƒ€μž… μ•ˆμ •μ„±μ„ 높일 수 μžˆμŠ΅λ‹ˆλ‹€.

    • JDK1.5 μ΄μ „μ—λŠ” Object νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ μ›ν•˜λŠ” 객체의 νƒ€μž…μœΌλ‘œ μΊμŠ€νŒ…ν•˜μ—¬ μ‚¬μš©ν•΄μ•Όλ§Œ ν–ˆκ³ , 잘λͺ»λœ μΊμŠ€νŒ…μœΌλ‘œ 인해 λŸ°νƒ€μž„ 였λ₯˜ λ°œμƒν•  κ°€λŠ₯성이 μžˆμŠ΅λ‹ˆλ‹€.

      public class Example {
        public static void main(String[] args) {
      
            // JDK 1.5 이전
            ArrayList arrayList = new ArrayList();
            arrayList.add("Hello");
            String str = (String)arrayList.get(0);      // μΊμŠ€νŒ… μ•ˆν•  μ‹œ, 컴파일 였λ₯˜ 
            System.out.println("Not Generic : "+str);
      
            ArrayList<String> stringArrayList = new ArrayList<>();
            stringArrayList.add("World");
            String str2 = stringArrayList.get(0);       // μΊμŠ€νŒ… 상관 μ—†λ‹€. => νƒ€μž… μ•ˆμ „μ„± 제곡
            System.out.println("Generic : "+str2);
        }
      }
    • μ°Έμ‘°(https://coding-factory.tistory.com/573)


    Generic 클래슀

    μžλ°”μ˜ μ œλ„ˆλ¦­ 클래슀의 κΈ°λ³Έ SyntaxλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

    public class Box<T>{
        private T t;
    }

    μœ„ μ˜ˆμ œμ—μ„œ μ‚¬μš©λœ Tλ₯Ό νƒ€μž… λ³€μˆ˜λΌκ³  ν•˜λ©°, μž„μ˜μ˜ μ°Έμ‘°ν˜• νƒ€μž…μ„ μ˜λ―Έν•©λ‹ˆλ‹€. νƒ€μž…μ˜ λ§€κ°œλ³€μˆ˜μ˜ 이름은 μ•„λ¬΄κ±°λ‚˜ 듀어가도 μƒκ΄€μ—†μ§€λ§Œ, κ³΅μ‹λ¬Έμ„œμ˜ Name Convention을 λ”°λ₯΄λŠ” 게 μ’‹μŠ΅λ‹ˆλ‹€.

    • E : 주둜 μžλ°” Collection framework에 μ‚¬μš©λ˜λŠ” Element
    • K : mapμ—μ„œ λ§€κ°œλ³€μˆ˜λ‘œ μ‚¬μš©λ˜λŠ” Key
    • V : mapμ—μ„œ λ§€κ°œλ³€μˆ˜λ‘œ μ‚¬μš©λ˜λŠ” Value
    • N : 숫자λ₯Ό λ‚˜νƒ€λ‚΄λŠ” Number
    • T : 일반적으둜 μ‚¬μš©ν•˜λŠ” μ œλ„€λ¦­ Type
    • S : λ‘λ²ˆμ§Έλ‘œ μ‚¬μš©ν•˜λŠ” 일반 μ œλ„€λ¦­ Type
    • U : μ„Έλ²ˆμ§Έλ‘œ μ‚¬μš©ν•˜λŠ” 일반 μ œλ„€λ¦­ Type
    • V : λ„€λ²ˆμ§Έλ‘œ μ‚¬μš©ν•˜λŠ” 일반 μ œλ„€λ¦­ Type
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class Example {
        public static void main(String[] args) {
            Box<Integer, String> box = new Box<Integer, String>();
            box.add(Integer.valueOf(10),"Hello World");
            System.out.printf("Integer Value :%d\n", box.getFirst());
            System.out.printf("String Value :%s\n", box.getSecond());
    
            Pair<String, Integer> pair = new Pair<>();
            pair.addKeyValue("1", Integer.valueOf(10));
            System.out.printf("(Pair)Integer Value :%d\n", pair.getValue("1"));
    
            CustomList<Box> list = new CustomList<Box>();
            list.addItem(box);
            System.out.printf("(CustomList)Integer Value :%d\n", list.getItem(0).getFirst());
        }
    }
    
    class Box<T, S> {
        private T t;
        private S s;
    
        public void add(T t, S s) {
            this.t = t;
            this.s = s;
        }
    
        public T getFirst() {
            return t;
        }
    
        public S getSecond() {
            return s;
        }
    }
    
    class Pair<K,V>{
        private Map<K,V> map = new HashMap<K,V>();
    
        public void addKeyValue(K key, V value) {
            map.put(key, value);
        }
    
        public V getValue(K key) {
            return map.get(key);
        }
    }
    
    class CustomList<E>{
        private List<E> list = new ArrayList<E>();
    
        public void addItem(E value) {
            list.add(value);
        }
    
        public E getItem(int index) {
            return list.get(index);
        }
    }
    

    μœ„μ˜ μ˜ˆμ‹œλŠ” κ³΅μ‹λ¬Έμ„œμ˜ 예제λ₯Ό 가지고 μ™”μŠ΅λ‹ˆλ‹€. λ‹€μŒκ³Ό 같은 Name Convention을 λ”°λ₯΄λ©΄ 되고, λͺ‡ 가지 μ£Όμ˜ν•  μ μœΌλ‘œλŠ” Generic νƒ€μž…μœΌλ‘œλŠ” Primitive Type은 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€. 즉, int ν˜•κ³Ό 같은 κΈ°λ³Έν˜• νƒ€μž…μ€ μ‚¬μš©ν•  수 μ—†κ³  Interger와 같은 μ°Έμ‘°ν˜• νƒ€μž…μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ, PairλΆ€λΆ„μ—μ„œ new둜 ν• λ‹Ήν•˜λŠ” λΆ€λΆ„μ—μ„œλŠ” νƒ€μž…μ„ λͺ…μ‹œν•˜μ§€ μ•Šμ•˜μ§€λ§Œ 였λ₯˜λŠ” λ‚˜νƒ€λ‚˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μžλ°” 7버전 μ΄ν›„λ‘œλŠ” νƒ€μž… 좔둠이 κ°€λŠ₯ν•˜μ—¬ new λ’€μ—μ„œλŠ” μƒλž΅μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€.


    Generic μΈν„°νŽ˜μ΄μŠ€

    public class Example {
        public static void main(String[] args) {
            GenericClass genericClass = new GenericClass();
            System.out.println(genericClass.print());
            // Hello world
        }
    }
    
    class GenericClass implements GenericInterface<String>{
        @Override
        public String print() {
            return "Hello world";
        }
    }
    
    interface GenericInterface<T>{
        T print();
    }

    μΈν„°νŽ˜μ΄μŠ€λ„ ν΄λž˜μŠ€μ™€ λ™μΌν•˜κ²Œ μΈν„°νŽ˜μ΄μŠ€λͺ… μ˜†μ— νƒ€μž… λ³€μˆ˜λ₯Ό μ§€μ •ν•˜μ—¬ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.


    Generic λ©”μ†Œλ“œ

    Generic λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ©”μ†Œλ“œμ˜ νŒŒλΌλ―Έν„°μ— μ—¬λŸ¬ νƒ€μž…μ„ λŒ€μž…ν•˜λ„λ‘ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. Generic λ©”μ†Œλ“œμ— μ „λ‹¬λœ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ„ 기반으둜 μ»΄νŒŒμΌλŸ¬λŠ” 적절히 λ©”μ†Œλ“œ ν˜ΈμΆœμ„ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

    • μ œλ„€λ¦­ λ©”μ†Œλ“œμ˜ νƒ€μž…λ³€μˆ˜λŠ” 리턴 νƒ€μž… μ•žμ— μ„ μ–Έλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.
    • νƒ€μž…λ³€μˆ˜λŠ” μ—¬λŸ¬ 개λ₯Ό κ°€μ§ˆ 수 있으며, κΈ°λ³Έ Name Convention을 λ”°λ¦…λ‹ˆλ‹€.
    • 일반 ν΄λž˜μŠ€μ—μ„œ μ œλ„€λ¦­ λ©”μ†Œλ“œλ₯Ό μ„ μ–Έν•  수 있고, νƒ€μž…λ³€μˆ˜λŠ” λ™μΌν•˜κ²Œ κΈ°λ³Έν˜•μ€ μ•ˆλ˜κ³ , μ°Έμ‘°ν˜•λ§Œ κ°€λŠ₯ν•©λ‹ˆλ‹€.
    import java.util.ArrayList;
    import java.util.Arrays;
    
    public class Example {
    
        public static <E> void printArray(ArrayList<E> array){
            for(E element : array){
                System.out.print(element+" ");
            }
            System.out.println();
        }
    
        public static void main(String[] args) {
            ArrayList<Integer> integerArrayList = new ArrayList<>(Arrays.asList(1,2,3,4,5));
            ArrayList<Double> doubleArrayList = new ArrayList<>(Arrays.asList(1.1,2.2,3.3,4.4,5.5));
            ArrayList<Character> characterArrayList = new ArrayList<>(Arrays.asList('a','b','c','d','e'));
    
            printArray(integerArrayList);
            printArray(doubleArrayList);
            printArray(characterArrayList);
        }
    }

    Bounded Type

    클래슀, μΈν„°νŽ˜μ΄μŠ€, λ©”μ†Œλ“œλ₯Ό μ œλ„€λ¦­μœΌλ‘œ μž‘μ„±ν•  λ•Œ, νƒ€μž… λ³€μˆ˜λ₯Ό μ œν•œν•˜κΈ° μœ„ν•΄μ„œλŠ” Bounded Type으둜 μ„ μ–Έν•΄μ•Ό ν•©λ‹ˆλ‹€.
    <T extends μƒμœ„νƒ€μž…> 으둜 νƒ€μž…λ³€μˆ˜λ₯Ό μ§€μ •ν•˜μ—¬ μƒμœ„νƒ€μž…μ˜ ν•˜μœ„ν΄λž˜μŠ€λ‘œλ§Œ μ œν•œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    public class Example {
        public static void main(String[] args) {
    
            // bounded λ‚΄μ˜ νƒ€μž…μ΄ μ•„λ‹ˆμ—¬μ„œ 컴파일 였λ₯˜ λ°œμƒ
            // BoundedGeneric<String> boundedGeneric = new BoundedGeneric<String>();
    
            BoundedGeneric<Integer> boundedGeneric = new BoundedGeneric<>();
            boundedGeneric.setT(Integer.valueOf(10));
            boundedGeneric.print();
    
        }
    }
    
    class BoundedGeneric<T extends Number>{
        T t;
    
        public void print(){
            System.out.println(t);
        }
    
        public void setT(T t){
            this.t = t;
        }
    }

    WildCard

    μžλ°”μ—μ„œ μ™€μΌλ“œ μΉ΄λ“œλž€ μ œλ„€λ¦­ λ©”μ†Œλ“œμ—μ„œ λ§€κ°œλ³€μˆ˜λ₯Ό 받을 λ•Œ, νƒ€μž…λ³€μˆ˜κ°€ μ•„λ‹Œ ? λ₯Ό μ‚¬μš©ν•˜μ—¬ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ„ μ œν•œν•˜λŠ” 것을 λ§ν•©λ‹ˆλ‹€.

    import java.util.Arrays;
    import java.util.List;
    
    public class Example {
    
        public static double sum(List<? extends Number> numberlist){
            double sum = 0.0;
    
            for(Number n : numberlist){
                sum+=n.doubleValue();
            }
            return sum;
        }
        public static void main(String[] args) {
            List<Integer> integerList = Arrays.asList(1,2,3);
            System.out.println("sum : "+sum(integerList));      // 6.0
    
            List<Double> doubleList = Arrays.asList(1.1,2.2,3.3);
            System.out.println("sum : "+sum(doubleList));       // 6.6
    
        }
    }

    λ§€κ°œλ³€μˆ˜λ‘œ List numberlist둜 μ„ μ–Έλ˜μ—ˆλ‹€κ³  가정해보면, String으둜 κ΅¬μ„±λœ 리슀트, Character둜 κ΅¬μ„±λœ λ¦¬μŠ€νŠΈκ°€ λ§€κ°œλ³€μˆ˜λ‘œ λŒ€μž…μ΄ λ˜λ”λΌλ„ 였λ₯˜κ°€ λ‚˜νƒ€λ‚˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ§Œμ•½ λ©”μ†Œλ“œμ—μ„œ Number ν•œμ—μ„œλ§Œ ν˜ΈμΆœν•  수 μžˆλŠ” λ©”μ†Œλ“œλ₯Ό μ‹€ν–‰ν•œλ‹€λ©΄ String, Character둜 κ΅¬μ„±λœ λ¦¬μŠ€νŠΈκ°€ λŒ€μž…λ  경우 λŸ°νƒ€μž„ 였λ₯˜κ°€ λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.
    이것을 λ°©μ§€ν•˜κΈ° μœ„ν•΄μ„œ WildCardλ₯Ό μ‚¬μš©ν•˜μ—¬ Number의 μžμ‹ν΄λž˜μŠ€λ‘œλ§Œ 이루어진 리슀트만 λŒ€μž…μ„ 받도둝 μ œν•œμ„ 두면 였λ₯˜λ₯Ό 방지할 수 μžˆμŠ΅λ‹ˆλ‹€.

    • <?> : λͺ¨λ“  ν΄λž˜μŠ€λ‚˜ μΈν„°νŽ˜μ΄μŠ€ λͺ¨λ‘ 올 수 μžˆμŠ΅λ‹ˆλ‹€.

    • <? extends μƒμœ„νƒ€μž…> : μƒμœ„νƒ€μž…μ˜ μžμ‹ν΄λž˜μŠ€λ§Œ κ°€λŠ₯ν•©λ‹ˆλ‹€.

    • <? super ν•˜μœ„νƒ€μž…> : ν•˜μœ„νƒ€μž…μ˜ λΆ€λͺ¨ν΄λž˜μŠ€λ§Œ κ°€λŠ₯ν•©λ‹ˆλ‹€.


    T extends vs ? extends

    λ°”μš΄λ””λ“œ νƒ€μž…κ³Ό μ™€μΌλ“œμΉ΄λ“œλ₯Ό κ³΅λΆ€ν•˜λ©΄μ„œ 두 κ°€μ§€μ˜ 차이점이 κΆκΈˆν•˜μ˜€μŠ΅λ‹ˆλ‹€. 저와 λ™μΌν•˜κ²Œ μ§ˆλ¬Έν•œ κΈ€μ—μ„œ λ‹΅λ³€ 받은 λ‚΄μš©μœΌλ‘œ μž‘μ„±ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

    private static <T extends Number> void processList(List<T> someList) {
        T n = someList.get(0);
        someList.add(1,n); //addition allowed.   
    }
    
    private static void processList2(List<? extends Number> someList) {
        Number n = someList.get(0);
        //someList.add(1,n);//Compilation error. Addition not allowed.
        processList(someList);//Helper method for capturing the wildcard
    }
    • λ°”μš΄λ””λ“œ νƒ€μž…μ˜ λ§€κ°œλ³€μˆ˜λŠ” elementλ₯Ό μΆ”κ°€ν•  수 μžˆμ§€λ§Œ, μ™€μΌλ“œμΉ΄λ“œμ—μ„œλŠ” λΆˆκ°€λŠ₯ν•©λ‹ˆλ‹€.
    • λ°”μš΄λ””λ“œ νƒ€μž…μ€ TλΌλŠ” νƒ€μž…λ³€μˆ˜λ₯Ό 가지고 μžˆμ–΄ λ©”μ†Œλ“œ λ‚΄μ—μ„œ Tλ₯Ό μ •μ˜ν•˜κ³  T λ‚΄λΆ€ 클래슀의 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” λ“±μ˜ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμ§€λ§Œ μ™€μΌλ“œμΉ΄λ“œμ—μ„œλŠ” νƒ€μž…μ— λŒ€ν•œ 핸듀이 μ—†κΈ° λ•Œλ¬Έμ— μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
    • μ°Έμ‘°(https://stackoverflow.com/questions/38944896/difference-between-bounded-type-parameter-t-extends-and-upper-bound-wildcard)

    Erasure

    μ œλ„€λ¦­ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ 일반적인 λ™μž‘μ„ μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄μ„œ μ»΄νŒŒμΌλŸ¬κ°€ 컴파일 νƒ€μž„μ— μ œλ„€λ¦­ λ§€κ°œλ³€μˆ˜λ₯Ό μ‹€μ œ 클래슀둜 λ°”κΎΈλŠ” type erasureλ₯Ό μ μš©ν•©λ‹ˆλ‹€. type erasureλŠ” μΆ”κ°€ 클래슀λ₯Ό μƒμ„±ν•˜μ§€ μ•Šκ³  λŸ°νƒ€μž„ μ‹œ μ˜€λ²„ν—€λ“œκ°€ μΌμ–΄λ‚˜μ§€ μ•Šλ„λ‘ ν•˜κ²Œ ν•΄μ£ΌλŠ” ν”„λ‘œμ„ΈμŠ€μž…λ‹ˆλ‹€. 이둜 인해 μ œλ„€λ¦­ ν”„λ‘œκ·Έλž˜λ°μ—μ„œμ˜ νƒ€μž… μ•ˆμ •μ„±μ„ κ°•λ ₯ν•˜κ²Œ 보μž₯ν•©λ‹ˆλ‹€.

    Type Erasure rules

    • bounded type으둜 λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•  κ²½μš°λŠ” Generic type을 bounded type으둜 λ³€κ²½ν•©λ‹ˆλ‹€.
    • λ°”μš΄λ“œ λ˜μ§€ μ•Šμ•˜λ‹€λ©΄ Generic type은 Object둜 λ°”κΏ‰λ‹ˆλ‹€.
    • νƒ€μž… μ•ˆμ •μ„±μ„ 보μž₯ν•˜κΈ° μœ„ν•΄ type castλ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.
    • ν™•μž₯된 generic typeμ—μ„œ λ‹€ν˜•μ„±μ„ μœ μ§€ν•˜κΈ° μœ„ν•œ bridge methodλ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.
    • μ°Έμ‘°(https://www.tutorialspoint.com/java_generics/java_generics_quick_guide.htm)
    public class Example {
       public static void main(String[] args) {
          Box<Integer> integerBox = new Box<Integer>();
          Box<Double> doubleBox = new Box<Double>();
    
          integerBox.add(new Integer(10));
          doubleBox.add(new Double(10.0));
    
          System.out.printf("Integer Value :%d\n", integerBox.get());
          System.out.printf("Double Value :%s\n", doubleBox.get());
       }
    }
    
    class Box<T extends Number> {
       private T t;
    
       public void add(T t) {
          this.t = t;
       }
    
       public T get() {
          return t;
       }   
    }

    λ‹€μŒμ€ μ œλ„€λ¦­μ„ μ΄μš©ν•œ μ½”λ“œμž…λ‹ˆλ‹€.

    public static void main(String[] args) {
          Box integerBox = new Box();
          Box doubleBox = new Box();
    
          integerBox.add(new Integer(10));
          doubleBox.add(new Double(10.0));
    
          System.out.printf("Integer Value :%d\n", integerBox.get());
          System.out.printf("Double Value :%s\n", doubleBox.get());
       }
    }
    
    class Box {
       private Number t;
    
       public void add(Number t) {
          this.t = t;
       }
    
       public Number get() {
          return t;
       }   
    }

    μžλ°” μ»΄νŒŒμΌλŸ¬λŠ” Erasure rule에 맞게 generic type을 μ‹€μ œ 클래슀둜 λ°”κΎΈκ²Œ 되고, λ‹€μŒ μ½”λ“œμ™€ 같은 λ°”μ΄νŠΈμ½”λ“œλ₯Ό μƒμ„±ν•˜κ²Œ λ©λ‹ˆλ‹€.

    λ°˜μ‘ν˜•

    'Android > Java' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

    [Java] λ””μžμΈ νŒ¨ν„΄(Strategy νŒ¨ν„΄)  (0) 2021.05.11
    [Java] λžŒλ‹€μ‹μ΄λž€?  (0) 2021.03.21
    [Java] Java IO, NIO  (0) 2021.02.22
    [Java] Annotation, Meta dataλž€?  (0) 2021.02.19
    [Java] Enumμ΄λž€?  (0) 2021.02.14
Designed by Tistory.