ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • day25_1 - JAVA (자바, Generic)
    KIC/JAVA 2021. 7. 19. 14:24
    반응형

    [제네릭 타입(Generic)]

    -> '컴파일 단계'에서 '잘못된 타입이 사용될 수 있는 문제'를 제거 가능

     

    -> 컬렉션, 람다식(함수적 인터페이스), 스트림, NIO에서 널리 사용

     

    -> 제네릭을 모르면 API 도큐먼트 해석이 어려우므로 학습이 필요하다.

     

    -> 일반적인 코드를 작성하고, 이 코드를 다양한 타입의 객체에 대하여 재사용하는 프로그래밍 기법이다.

     

    ->  클래스에서 사용할 타입을 클래스 외부에서 설정하는 타입이다.

     

     

     

     

     

    [제네릭을 사용하는 코드의 이점]

    -> 컴파일 시 강한 타입 체크가 가능

     

    -> 컴파일 시에 미리 타입을 강하게 체크해서 에러를 사전에 방지한다.

     

     

    [ex]

    package javaPro.java_generic;
    
    class MyClass01{
    
        @Override
        public String toString() {
            return "MyClass01 문장 실행";
        }
    }
    
    class Pool01 {
        private Object object;
    
        public void set(Object object) {
            this.object = object;
        }
    
        public Object get(){
            return object;
        }
    }
    
    public class GenericEx01 {
        public static void main(String[] args) {
            Pool01 gen = new Pool01();
            gen.set("그랜저"); // Object <------- String type
            String name = (String)gen.get();    
            // get() 으로 받아오는 타입이 Object 이므로 name에 저장할때 (String)으로 형변환 필요
    
            System.out.println(name);
    
            gen.set(new MyClass01()); // Object <---------- MyClass type
            MyClass01 g = (MyClass01)gen.get(); 
            // get() 으로 받아오느 타입은 이역시 object 이므로 g에 저장할 때 (MyClass01)타입으로 형변한 필요
    
    
            //String g2 (String) gen.get();  //이 문장은 error
    
            System.out.println(g); // g에 저장된 MyClass01 메서드 실행
    
        }
    }

     

     

     

     

    [제네릭 타입]

    -> 타입을 파라미터로 가지는 클래스와 인터페이스

     

    => 선언 시 클래스 또는 인터페이스 이름 뒤에 '<>' 부호를 붙인다.

     

    -> '<>' 사이에는 타입 파라미터 위치

     

    타입 파라미터

    -> 일반적으로 대문자 알파벳 한 문자로 표현

     

    -> 개발 코드에서는 타입 파라미터 자리에 구체적인 타입을 지정해야 한다.

     

     

     

     

    [제네릭 타입을 사용하지 않은 경우]

    -> Object 타입 사용 -> 빈번한 타입 변환 발생 -> 프로그램 성능 저하

     

     

     

    -> 제네릭은 타입이 Box 오브젝트로 들어가기 전부터 미리 타입을 사용자가 지정해서 집어넣는 기능이다.

     

     

     

     

     

    [제네릭 타입을 사용한 경우]

    -> 클래스를 선언할 때 타입 파라미터를 사용

     

    -> 컴파일 시 타입 파라미터가 구체적인 클래스로 변경된다.

     

    package javaPro.java_generic;
    
    /*
    제네릭을 이용 
    타입을 정하지 않고  class를 구현하는 방법이다 
    class의 멤버, 메소드 파라메터, 리턴 타입, 인터페이스의 타입을 실행시에 적용 할 수 있다
    실행 사용시 제네릭 생략가능함  
    
    */
    
    class Pool02<T> {
        private T t;
    
        public void set(T t) {
            this.t = t;
        }
    
        public T get(){
            return t;
        }
    }
    
    public class GenericEx02 {
        public static void main(String[] args) {
            // 제네릭 클래스이기 때문에 <String>를 지정해줘야 error가 안난다.
            Pool02<String> p = new Pool02<String>();
            p.set("hello");
            System.out.println(p.get());
    
            String str = p.get(); //이전 GenericEx1 코드와 다르게 (String) 형변환이 필요 없다.
            System.out.println(str);
            
            Pool02<Integer> p2 = new Pool02<Integer>();
            p2.set(1);
            System.out.println(p2.get());
            int value = p2.get();
    
            System.out.println(value);
    
        }
    }

     

     

     

     

     

     

     

    [제네릭 타입은 두 개 이상의 타입 파라미터를 사용 가능]

    [ex]

    package javaPro.java_generic;
    
    /*
    제네릭 : <T, M> 은 모든 문자가 가능 하다. 주로 영문 대문자 한글자를 쓴다
     *제네릭 class 구현  
     */
    
    class Product<T, M> {
        private T kind;
        private M model;
    
        public T getKind() {
            return this.kind;
        }
    
        public void setKind(T kind) {
            this.kind = kind;
        }
    
        public M getModel() {
            return this.model;
        }
    
        public void setModel(M model) {
            this.model = model;
        }
    
        public String toString() {
            return "Product [kind =" + kind + ", model = " + model + "]";
        }
    }
    
    class Car {
        public String toString() {
            return "Car";
        }
    }
    
    class Tv {
        public String toString() {
            return "Tv";
        }
    }
    
    public class GenericEx3 {
        public static void main(String[] args) {
            Product<Tv, String> product1 = new Product<Tv, String>();
            product1.setKind(new Tv()); // 메소드를 매개변수로 받아 저장
            product1.setModel("스마트Tv"); // String 을 매개변수로 받아 저장
            Tv tv = product1.getKind(); // 리턴 값이 tv 메서드
            String tvModel = product1.getModel(); // 리턴 값이 String
            System.out.println("Tv 메서드 결과값: " + tv + "\n" + "tvModel 변수 저장값: " + tvModel);
            System.out.println(product1);
    
            Product<Car, String> product2 = new Product<Car, String>();
            product2.setKind(new Car());
            product2.setModel("디젤");
    
            Car car = product2.getKind();
            String carModel = product2.getModel();
            System.out.println("Car 메서드 결과값: " + car + "\n" + "carModel 변수 저장값: " + carModel);
            System.out.println(product2);
        }
    }

     

     

    자바 7부터는 다이아몬드 연산자를 사용해 간단히 작성 가능

     

     

     

    [제네릭 메소드]

    -> 매개변수 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드

     

    -> 제네릭 메소드 선언 방법

       -> 리턴 타입 앞에 '<>' 기호를 추가하고 타입 파라미터를 기술

       -> 타입 파라미터를 리턴 타입과 매개변수에 사용한다.

    [ex]

    package javaPro.java_generic;
    
    /* 
     * 제네릭  Method구현 : class 이용 하지 않고 메소드만을 제네릭으로 구현한다 
     * 실행 사용시 제네릭 생략가능함 
     * 
     * 
     */
    
    class Pool04<T> {
        private T t;
    
        public void set(T t) {
            this.t = t;
        }
    
        public T get() {
            return t;
        }
    }
    // 다양 한 방식의 메소드들을 Generic으로 구현한 코드
    
    class Util04 {
        public static <T> Pool04<T> staticMethod(T t) {
            Pool04<T> box = new Pool04<T>();
            box.set(t);
            return box;
        }
    
        public <T> Pool04<T> instanceMethod1(T t) {
            Pool04<T> box = new Pool04<T>();
            box.set(t);
            return box;
        }
    
        public <T> String instanceMethod2(T t) {
            return t.toString();
        }
    }
    
    class MyCar {
        public String toString() {
            return "MyCar";
        }
    }
    
    public class GenericEx4 {
        public static void main(String[] args) {
            Pool04<Integer> box1 = Util04.<Integer>staticMethod(100); // 제네릭 생략 가능
            int intValue = box1.get();
            System.out.println(intValue);
    
            Util04 u = new Util04(); // 제네릭을 생략했기 때문에 어떤 값이든 가능
    
            Pool04<String> box2 = u.<String>instanceMethod1("홍길동"); // 생략 가능
            String strValue = box2.get();
            System.out.println(strValue);
            System.out.println(u.instanceMethod2(100)); // 정수 문자 메소드 다 잘 들어간다.
            System.out.println(u.instanceMethod2("김자바"));
            System.out.println(u.instanceMethod2(new MyCar()));
        }
    }

     

     

     

     

    [제네릭 타입 제한하기]

    package javaPro.java_generic;
    
    class Pool05<T extends Number> { // Number를 상속받은 타입으로만 제한하겠다는 의미
        T v;
        Pool05(T n){
            v = n;
        }
        void set(T n) {
            v = n;
        }
        T get() {
            return v;
        }
    }
    
    class Util05 {
        public static <T extends Number> int compare(T t1, T t2) {
            double v1 = t1.doubleValue();
            // System.out.println(t1.getClass().getName());
            double v2 = t2.doubleValue();
            // System.out.println(t2.getClass().getName());
            return Double.compare(v1, v2); // compare: 앞이 크면 1 출력 , 뒤가 크면 -1 출력
        }
    
    }
    
    public class GenericEx5 {
        public static void main(String[] args) {
            // 제네릭 클래스는 <> 생략이 가능하다.
    
            //T는 Number를 상속받는 타입으로만 제한했기 때문에 String 타입은 error
            //String str = Util05.compare("a", "b");
    
            int result1 = Util05.<Integer>compare(10, 20);
            System.out.println(result1); //1 출력
            int result2 = Util05.compare(4.5, 3);
            System.out.println(result2); //-1 출력
    
            Pool05<Integer> p1 = new Pool05<Integer>(20);
            Pool05<Double> p2 = new Pool05<Double>(20.0);
    
            //제네릭 에서 T는 Number를 상속받는 타입으로만 제한했기 때문에 String 타입과 Character은 error
            //Pool05<String> p3 = new Pool05<String>("hello"); 
            //Pool05<Character> p4 = new Pool05<Character>('a');
            
            Pool05<Byte> p5 = new Pool05<Byte>((byte) 1);
            int value = p1.get();
            System.out.println(value);
            System.out.println(p2.get());
            System.out.println(p5.get());
        }
    }

     

     

     

    [제네릭 타입 배열 입력]

    package javaPro.java_generic;
    
    //제네릭 타입 배열 입력하기 구현
    
    class Generic1<T> {
        T[] v;
    
        public T[] getV() {
            return this.v;
        }
    
        public void setV(T[] v) {
            this.v = v;
        }
    
        public void print() {
            for (T s : v)
                System.out.print(s + ",");
            System.out.println();
        }
    }
    
    public class GenericEx7 {
        public static void main(String[] args) {
            Generic1<String> t = new Generic1<String>();
            String[] ss = { " 월매 ", " 순향 ", " 향단 " };
            t.setV(ss);
            t.print();
            for (String s : t.getV())
                System.out.println(s.trim());
            Integer[] ii = { 10, 20, 30 };
            // t.set(ii); // 지금 t는 String 타입이기 때문에 Integer 넣으면 오류
    
            Generic1<Integer> t2 = new Generic1<Integer>();
            t2.setV(ii);
            t2.print();
            for (Integer s : t2.getV())
                System.out.println(s / 10);
        
            }
    }
    300x250

    댓글

Designed by Tistory.