티스토리 뷰

1.    제네릭 타입이란?

-      타입을 파라미터(매개변수)로 가지는 클래스와 인터페이스다.

-      선언 시 클래스 또는 인터페이스 이름 뒤에 < 타입 파라미터 >로 적는다.

-      제네릭 타입을 사용하지 않는 경우 :

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

-      제네릭 타입을 사용하는 경우 :

-      1 ) 클래스 선언할 때 타입 파라미터 사용하면,

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

 

2.    제네릭 타입을 사용할 때 주의점

-      제네릭 타입을 선언할 때에는 타입 파라미터를 선언하는 것이다.

-      그렇기에 파라미터의 이름도 단문 대문자 알파벳 1글자로 선언하는 것이다.

-      제네릭 타입을 사용할 때에는 타입파라미터에 참조타입의 이름을 값으로 전달하는 것이다. ( 전달인자 )

-      사용 ex ) Box<String> box1 = new Box<String>();

-      사용 ex ) Box<Integer> box2 = new Box<Integer>();

-      이때 전달한 참조타입 이름을 구체타입이라고 한다.

-      (1) 제네릭 타입으로 객체를 생성할 때

-      (2) 제네릭 타입의 변수를 선언할 때

-      (3) 제네릭 메소드를 호출할 때

 

3.    정수타입과 참조타입( Wrapper Type )

-      1 ) 정수타입

-      byte ------------------------------->  Byte

-      char -------------------------------> Character

-      short -------------------------------> Short

-      int  -------------------------------> Integer

-      long -------------------------------> Long

-      2 ) 실수타입

-      float -------------------------------> Float

-      double -------------------------------> Double

-      3 ) 논리

-      Boolean ------------------------------->  Boolean

-      Wrapper Type( 포장클래스 )은 클래스타입에 속한다.

-      포장 객체 : 기본타입 값을 내부에 두고 포장하는 객체이다.

-      포장 객체에서는 기본 타입의 값은 외부에서 변경이 불가능하다.

-      Boxing : 기본 타입의 값을 포장 객체로 만드는 과정

-      Unboxing : 포장 객체에서 기본 타입의 값을 얻어내는 과정이다.

 

4.    멀티 타입 파라미터

-      제네릭 타입은 1개 이상의 타입 파라미터를 사용할 수 있다!

-      각 타입 파라미터의 구분은 콤마 , 로 구분한다.

-      Ex. public class Product < T, M > { }

-      Ex. Product< Tv, String > Product = new Product< >( );

 

5.    제네릭 메소드

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

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

-      리턴 타입 앞에 “ < > “을 추가하고 타입 파라미터를 작성한다.

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

-      Ex. public < 타임 파라미터 > 리턴 타입 메소드명 ( 매개변수 ) { … }

-      Ex. public < T > Box <T> boxing (T t) { … }

-      제네릭 메소드 호출하는 방법 :

-      Ex. Box < Integer > box = < Integer > boxing(100) ;

-      Ex. Box < Integer > box = boxing (100) ;

 

6.    제한된 타입 파라미터 ( Bounded )

-      타입 파라미터에 지정되는 구체적인 타입 제한하기 위해 사용한다.

-      사용하는 이유는 제네릭은 어떤 타입이라도 올 수 있는데, 그렇게 되면 코드가 이상하게 작성될 수 있기에 이를 예방하는 차원에서 사용한다.

-      상속 및 구현 관계를 이용해서 구체 타입을 제한한다.

-      Ex. public < T extends 상위타입 > 리턴 타입 메소드 ( 매개변수 ) { … }

-      상위 타입은 클래스 뿐만이 아니라 인터페이스도 가능하다.

 

7.    와일드카드 타입 <?>

-      와일드 카드는 구체타입을 하나만 지정하지 않고, 폭넓게 사용하기 위해서 생겨났다.

-      와일드 카드 타입의 3가지 형태 :

-      1. 제네릭타입<?>은 제한이 없다는 의미이다.

-      , 타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스나 인터페이스 타입이 올 수 있다.

-      2. 제네릭타입< ? extends 상위타입 >상위 클래스로 제한한다는 의미이다.

-      타입 파라미터를 대치하는 구체적인 타입으로 상위타입이나 하위 타입만 올 수 있다.

-      3. 제네릭타입 < ? super 하위타입 >하위 클래스로 제한한다는 의미이다.

-      , 타입 파라미터를 대치하는 구체적인 타입으로 하위타입이나 상위타입이 올 수 있다.

 

8.    제네릭 타입의 상속과 구현

-      제네릭 타입은 상속과 구현이 가능하다.

-      제네릭 타입을 부모 클래스로 사용할 경우 :

-      타입 파라미터는 자식 클래스에도 기술해야 하고, 추가적인 타입파라미터를 가질 수 있다.

-      Ex. public class ChildProduct < T,M,C > extends Product < T, M > { … }


01. 제네릭 타입

 

package generic_type;

 

public class Apple {

      

       ;;

 

} // end class


package generic_type;

 

public class Box {

      

       private Object object;

      

       public void set ( Object object ) { // 이때 Object는 모든 객체의 조상인 그 Object를 의미하기에 뭐든지 들어갈 수 있다.(**)

             this.object = object; // ( Lvalue는 부모객체,  Rvalue는 자식객체이다 )

       } // setter

      

       public Object get () {

             return object;

       } // getter

 

} // end class


package generic_type;

 

public class BoxExample {

      

       public static void main(String[] args) {

            

             Box box = new Box();

            

             box.set("홍길동"); // 다형성1

             String name = (String) box.get(); // object타입을 string타입으로 강제형변환시키고 있다.

            

//           ========================================

            

             box.set(new Apple()); // 다형성1

             Apple apple = (Apple) box.get(); // object타입을 Apple타입으로 강제형변환시키고 있다.

            

       } // main

 

} // end class

 

02. 제네릭 클래스

 

package generic_type02;

 

import lombok.NoArgsConstructor;

import lombok.ToString;

 

// Generic Type 중, 제네릭을 클래스에 적용 = " 제네릭 클래스 "

 

@ToString // ToString의 결과 : Box(t=hello)

@NoArgsConstructor

public class Box<T> { // 이때 T는 타입 파라미터(매개변수)이며, T대신 다른 참조변수가 들어갈 수 있다.

          

           // 필드 선언

           private T t; // 필드의 타입을 T로 하였다.

          

           // 생성자는 존재하지 않는다. - > 롬복 사용!

           // 롬복을 사용했다면 outline을 통해 생성되었는지 확인하는 것이 좋다!

          

           // 메소드(getter, setter) 선언

           public T get() {return t;} // getter

           public void set ( T t) { this.t = t; } // setter

 

} // end class


package generic_type02;

 

 

public class BoxExample {

      

      

       public static void main (String [] args) {

            

             // 제네릭타입 클래스로부터 인스턴스 생성

             Box<String> box1 = new Box<String>(); // 1. 자바 7까지의 방법 (***)

             // < 타입파라미터 >에는 참조타입을 줘야 하는데, 이때는 String타입으로 준것이다. (**)

             // 이렇게 되면 <T>는 다형성으로 인한 변환이 아니라 단순히 String을 담는 것이 된다.

            

             Box<String> box3 = new Box<>(); // 2. 자바 8 이후 생겨난 방법 (***)

             // Rvalue < > : 타입추론 연산자

             // 자바 8이후에는 Rvlaue < > 안을 생략하는 것이 가능하다. 이를 적극적으로 사용하자!

            

             box1.set("hello");                                   // Setter 메소드 호출

             String str = box1.get();                       // Getter 메소드 호출

            

             System.out.println("box1 : " + box1); // 출력 : box1 : Box(t=hello)

            

//           =============================================

            

             // 제네릭타입 클래스로부터 인스턴스 생성

             Box<Integer> box2 = new Box<Integer>();  // 1. 자바 7까지의 방법 (***)

             // 여기에서는 타입파라미터인 <T>에다가 Integer타입(int)을 준 것이다.

            

             Box<Integer> box4 = new Box<>(); // 2. 자바 8 이후 생겨난 방법 (***)

            

             box2.set(6);                                   // Setter 메소드 호출

             int value = box2.get();                        // Getter 메소드 호출

            

             System.out.println("box2 : " + box2); // 출력 : box2 : Box(t=6)

            

       } // main

      

//     =========================================================================

      

       // 정수타입 (***) :                                  참조타입 ( Wrapper Type )

       // byte -------------------------------> Byte

       // char -------------------------------> Character

       // short ------------------------------> Short

       // int --------------------------------> Integer

       // long -------------------------------> Long

      

       // 실수타입 (***) :                                  참조타입 ( Wrapper Type )

       // float  -------------------------------> Float

       // double  ------------------------------> Double

      

       // 논리참조 (***) :                                  참조타입 ( Wrapper Type )

       // boolean  ------------------------------> Boolean

 

} // end class

 

03. 제네릭 메소드

 

package generic_method;

 

import lombok.Getter;

import lombok.NoArgsConstructor;

import lombok.Setter;

import lombok.ToString;

 

@ToString

@Getter @Setter

@NoArgsConstructor

public class Box <T> {

      

       private T t;

      

       // Getter Setter를 롬복으로 생성하였다.

      

//     public T get() { return t; }

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

 

} // end class


package generic_method;

 

public class Util { // Utility class - > Helper class : 작은 기능들을 호출할 수 있게 정적 메소드로 구현

                                 // ex. Math.random

      

       // 제네릭 메소드 선언

       public static <T> Box <T> boxing ( T t ) {

            

//           Box<T> box = new Box<T>();

             Box<T> box = new Box<>();

            

             box.setT(t);

             return box;

            

       } // Boxing

 

} // end class


package generic_method;

 

public class BoxingMethodExample {

      

       public static void main (String[] args) {

            

             // Utility class에 선언된 제네릭 정적 메소드 호출 (*****)

             Box<Integer> box1 = Util.<Integer>boxing(100); // Box제네릭 클래스에 있는 Box<T>에 Util클래스에 있는 제네릭 메소드를 사용하였다.

//           Box<Integer> box2 = Util.boxing(100); // 새로나온 방법이다. 익숙해지기 전까지는 전부 치는 방법을 사용하자.

            

             int intValue = box1.getT();

            

             System.out.println("box1 : " + box1); // 출력 : box1 : Box(t=100)

            

//           =====================================================

            

             Box<String> box2 = Util.<String>boxing("홍길동");

             String strValue = box2.getT();

            

             System.out.println("box2 : " + box2); // 출력 : box2 : Box(t=홍길동)

            

       } // main

 

} // end class

 

04. 제네릭 메소드 2 - 멀티타입

 

package generic_method02;

 

public class Pair <K, V> {

      

       private K key;

       private V value;

      

       public Pair ( K key, V value) {

             this.key = key;

             this.value = value;

       } // constructor

      

       public void setKey(K key) { this.key = key; }

       public void setValue(V value) { this.value = value; }

       public K getKey() {return key;}

       public V getValue() {return value;}

 

} // end class


package generic_method02;

 

public class Util {

      

       public static <K,V> boolean compare(Pair<K,V>p1,Pair<K,V>p2) {

            

             boolean KeyCompare = p1.getKey().equals(p2.getKey());

             boolean valueCompare = p1.getValue().equals(p2.getValue());

             return KeyCompare & valueCompare;

            

       } // end

 

} // end class


package generic_method02;

 

public class CompareMethodExample {

      

       public static void main (String[] args) {

            

             Pair<Integer,String> p1 = new Pair<Integer,String>(1,"anj");

             Pair<Integer,String> p2 = new Pair<Integer,String>(1,"anj");

            

             boolean result1 = Util.<Integer,String>compare(p1,p2);

            

             if(result1) {

                    System.out.println(" ");

             } else {

                    System.out.println(" ");

             } // if- else

            

       } // main

 

} // end class

 

05. 멀티 타입 파라미터 (  매개변수 )

 

package multi_type_parameter;

 

import lombok.NoArgsConstructor;

 

@NoArgsConstructor

public class Car {

      

       ;;

 

} // end class


package multi_type_parameter;

 

import lombok.NoArgsConstructor;

 

@NoArgsConstructor

public class Tv {

      

       ;;

 

} // end class


package multi_type_parameter;

 

import lombok.Getter;

import lombok.NoArgsConstructor;

import lombok.Setter;

import lombok.ToString;

 

// 제네릭 타입 클래스 선언 - T, M이라는 멀티타입 파라미터를 가지고 있다!

@ToString

@Getter @Setter

@NoArgsConstructor

public class Product < T, M > {

      

       private T kind;

       private M model;

      

       // 생성자가 없다! - > 롬복 사용!

      

      // 밑의 코드 대신 롬복을 통해 @Getter @Setter로 생성하면 코드가 간단해진다!!(**)

      

//     public T getKind() { return this.kind; }

//     public M getModel() { return this.model; }

      

//     public void setKind ( T kind ) { this.kind = kind; }

//     public void setModel ( M model ) { this.model = model; }

 

} // end class


package multi_type_parameter;

 

public class ProductExample {

      

       public static void main (String[] args) {

            

             // 제네릭타입클래스의 인스턴스 생성 ( so, 구체타입을 전달해야 한다!! )

            

//           Product < Tv, String > product1 = new Product<Tv,String>(); // 구버전

             Product < Tv, String > product1 = new Product<>();

            

             // setter

             product1.setKind(new Tv()); // 타입을 Tv라고 하였기에

             product1.setModel("스마트 TV");

            

             // getter

             Tv tv = product1.getKind();

             String tvModel = product1.getModel();

            

             System.out.println("product1 : " + product1); // 출력 : product1 : Product(kind=multi_type_parameter.Tv@2f92e0f4, model=스마트 TV)

            

//            ============================================================================

            

//           Product <Car, String > product2 = new Product <Car,String>(); // 구버전

             Product <Car, String > product2 = new Product <>();

            

             //setter

             product2.setKind(new Car()); // 타입을 Car라고 하였기에

             product2.setModel("디젤");

            

             // getter

             Car car = product2.getKind();

             String carModel = product2.getModel();

            

             System.out.println("prosuct2 : " + product2); // 출력 : prosuct2 : Product(kind=multi_type_parameter.Car@5305068a, model=디젤)

            

       } // main

 

} // end class

 

06. 박싱과 언박싱

 

package wrapper;

 

public class BoxingUnBoxingExample { // 박싱과 언박싱 (****)

      

       public static void main (String[] args) {

            

             // 1. Boxing

             Integer obj1 = new Integer(100); // Deprecated

             Integer obj2 = new Integer("200"); // Deprecated

            

             // 이렇게 취소선이 생기는 것을  Deprecated라고 한다. (**)

             // 이러한 의미는 중요도가 점점 떨어져서 업데이트가 되면 제거될 수 있으니 사용하지 말라는 의미이다.

             // 이는 사용하지 않는 것이 좋다.

            

             Integer obj3 = Integer.valueOf("300"); // Boxing의 새로운 방법 (****)

             // valueOf()는 정수를 담고 있는 문자열이라면 이를 Integer 객체로 주겠다는 의미이다.

             // 이 방법을 사용해서 Boxing을 하자!

            

             // 2. Unboxing (***)

             int value1 = obj1.intValue();

             int value2 = obj2.intValue();

             int value3 = obj3.intValue();

            

             System.out.println(value1);

             System.out.println(value2);

             System.out.println(value3);

            

             // 포장 객체는 내부 값을 비교하기 위한 ==와 != 연산자를 사용하는 것이 불가능하다!

             // 참조타입은 값을 비교하는 것이 아니라 주소를 가지고 비교하게 되기에

             // 값을 언박싱을 하여 비교하거나 equals()를 사용해야 한다!! (**)

            

             // 3. Boolean의 박싱 / 언박싱

            

             Boolean bool1 = Boolean.valueOf("true"); // valueOf은 문자열로 부터 wrapper type의 값을 만들어 낸다. (****)

             Boolean bool2 = Boolean.valueOf(false);

            

             // valueOf(  ) 안에는 문자열을 넣을 수도 있는데,

             // 만약 문자열에 true / false 외에 다른 것이 들어가도 이는 컴파일러가 체크하지는 못하고 실행할때 예외가 발생한다.

            

             Boolean bool3 = new Boolean(true); // Deprecated

             Boolean bool4 = new Boolean("false"); // Deprecated

            

             Boolean bool5 = Boolean.parseBoolean("false"); // parsexxx는 문자열로 부터 기본타입의 값을 만들어 낸다. (****)

             System.out.println("bool5 : " + bool5);

            

             // parse + 기본타입 명은 대응되는 기본타입 값으로 변환해서 return해주는 정적메소드이다.

            

//          

            

             boolean b1 = bool1.booleanValue();

             boolean b2 = bool2.booleanValue();

             boolean b3 = bool3.booleanValue();

             boolean b4 = bool4.booleanValue();

            

             // Auto-boxing / Auto-unboxing (****)

            

             // 자동 박싱 : 포장 클래스 타입에 기본값이 대입될 경우 발생한다.

             // 자동 언박싱 : 기본타입에 포장 객체가 대입될 경우 발생한다.

            

             Integer i = 1000; // Auto-boxing

             // Lvalue는 참조타입 Rvalue는 기본타입인데 참조타입이 기본타입보다 크기에 자동형변환이 일어난다. (**)

             // 하지만 이러한 자동형변환은 wrapper type에서만 일어나고, 다른 참조타입에서는 발생하지 않는다.

            

             int i2 = i; // Auto-unboxing

//           int i2 = i.intValue(); // Auto-unboxing

             // 위의 2개의 식은 같은 식으로 컴파일러가 자동으로 .intValue()을 작성하여 자동으로 값을 꺼내는 것이다.

             // 이때는 강제형변환은 일어나지 않는다.

            

       } // main

 

} // end class

 

07. 박싱한 값의 비교

 

package wrapper;

 

public class ValueCompareExample { // 박싱한 값을 비교하기!

      

       public static void main(String [] args) {

            

             System.out.println(" [ -128 ~ 127 초과값일 경우 ] ");

             // byte, short, int 값을 가진 wrapper 객체는 -128 ~ 127 안의 값만 비교가 가능하다.

             // 그냥 언박싱을 통해서 비교하는 것이 좋다!!(**)

            

             Integer obj1 = 300;

             Integer obj2 = 300;

             System.out.println(" == 결과 : " + (obj1 == obj2)); //  == 결과 : false

             System.out.println("언박싱한 후 == 결과 : " + (obj1.intValue() == obj2.intValue())); // 언박싱한 후 == 결과 : true (**)

             System.out.println("eaqual() == 결과 : " + obj1.equals(obj2)) ; // eaqual() == 결과 : true (****)

             System.out.println();

            

//       =======================================================================================

            

             System.out.println( " [ -128 ~ 127 범위값일 경우 ]  "); // 범위 내의 값이라서 값은 잘 나오지만 사용하지 않는 것이 좋다.

             Integer obj3 = 10;

             Integer obj4 = 10;

             System.out.println(" == 결과 : " + (obj3 == obj4)); //  == 결과 : true

             System.out.println("언박싱한 후 == 결과 : " + (obj3.intValue() == obj4.intValue())); // 언박싱한 후 == 결과 : true (**)

             System.out.println("eaqual() == 결과 : " + obj3.equals(obj4)) ; // eaqual() == 결과 : true (****)

             System.out.println();

            

            

       } // main

 

} // end class

 

08. 제네릭 상속

 

package generic_extends;

 

import lombok.Getter;

import lombok.NoArgsConstructor;

import lombok.Setter;

import lombok.ToString;

 

 

@ToString

@Getter @Setter

@NoArgsConstructor

public class ChildProduct <T,M,C> extends Product <T,M> {

      

private C company; // T와 M은 상속 받고 있으며, C는 자기 자신만의 것으로 생성하였다.

 

} // end class

 

09. 와일드 카드 1

 

package generic_wildCard;

 

import lombok.Getter;

 

// 제한된 파라미터 중 와일드카드를 이해하기 위한 예제

@Getter

public class Course <T> { // 학원의 모든 과정을 대표하는 클래스

      

       private String name; // 과정명

       private T[] students; // 수강생 ( 재직자, 학생, 실업자 )

                                         // 필드의 타입이 배열인데, T타입의 배열이다.

      

       public Course(String name, int capacity) { // 과정명과 수용가능인원을 받는다.

            

             this.name = name; // 필드 초기화

            

             // 제네릭 타입파라미터 배열 생성은 아래와 같이 2단계로 배열을 생성합니다. (*****)

             // 1. 우선 object타입의 원소를 가지고 있는 배열을 생성합니다.

             // 2. 강제형변환을 통해서 배열의 원소가 T인 배열로 변환합니다.

            

             students = (T[]) (new Object[capacity]); // T타입의 배열로 강제형변환

            

       } // constructor

      

       // Getter Setter은 롬복을 잘 사용하자!

      

//     public String getName() {return name;} // getter

//     public T[] getStudents() {return students;} // getter

      

       public void add(T t) { // 수강생을 모집할 때마다, 학생배열에 추가한다.

            

             for (int i=0; i<students.length; i++) {

                   

                    if(students[i] == null) { // 수강가능한 인원 중 빈자리가 있다면

                           students[i] = t; // 빈바리에 학생을 추가하는 코드

                           break;

                    } // if

                   

             } // for

            

       } // add

 

} // end class


package generic_wildCard;

 

public class HighschoolStudent extends Student {

      

       public HighschoolStudent (String name ) {

             super(name);

       } // constructor

 

} // end class


package generic_wildCard;

 

import lombok.Getter;

import lombok.ToString;

 

@Getter @ToString

public class Person {

      

       private String name;

      

       public Person(String name) {

             this.name = name;

       } // constructor - - - > @NoArgsConstructor은 이미 생성자가 만들어졌기에 작성이 불가능하다.

      

       // 아래의 2개의 식은 lombok이 대채하였다.

      

//     public String getName() { return name; }

//     public String toString() { return name; }

 

} // end class


package generic_wildCard;

 

public class Student extends Person {

      

       public Student (String name) {

             super(name);

       } // constructor

 

} // end class


package generic_wildCard;

 

 

public class Worker extends Person {

      

       public Worker(String name) {

             super(name);

       } // constructor - - -> 롬복은 필드가 있어야 하는데, 없어서 사용이 불가능 하다.

      

       // @NoArgsConstructor은 상속된 필드는 인식해서 만들어주지 못한다.

 

} // end class


package generic_wildCard;

 

import java.util.Arrays;

 

public class WildExample { // 제네릭 와일드카드

      

       // 모든 사람이 들을 수 있는 일반인 과정 등록 메소드 All (***)

       public static void registerCourse(Course<?>course) {

             System.out.println(course.getName() + " 수강생 : " + Arrays.toString(course.getStudents()));

       } //registerCourse

      

       // 학생만을 대상으로 하는 학생과정 등록 메소드 - 학생이거나 학생의 자식 ( 위를 막아두었다. ) (***)

       public static void registerCourseStudent(Course<? extends Student>course) { // upper bounded

             System.out.println(course.getName() + " 수강생 : " + Arrays.toString(course.getStudents()));

       } //registerCourseStudent

      

       // 재직자를 대상으로 하는 등록 메소드 - 재직자를 포함 재직자의 부모는 가능 ( 아래를 막아두었다. ) (***)

       public static void registerCourseWorker(Course<? super Worker>course) { // lower bounded

             System.out.println(course.getName() + " 수강생 : " + Arrays.toString(course.getStudents()));

       } //registerCourseWorker

      

       public static void main(String[] args) {

            

             Course<Person> personCource = new Course<Person>("일반인 과정",5); // Person타입을 받는 배열

            

             // = Course<?>course = new Course<Person>("일반인 과정",5);

            

             personCource.add(new Person("일반인")); //  OK!

             personCource.add(new Worker("직장인")); // OK! - 다형성1

             personCource.add(new Student("학생")); // OK! - 다형성1

             personCource.add(new HighschoolStudent("고등학생")); // OK! - 다형성1

            

             // why? Person은 부모이기에 모든 타입을 받아들일 수 있다. - 다형성1

            

             WildExample.registerCourse(personCource); // - registerCourse

             // 출력 : 일반인 과정 수강생 : [Person(name=일반인), Person(name=직장인), Person(name=학생), Person(name=고등학생), null]

            

//           WildExample.registerCourseStudent(personCource);

             // xx : 학생이거나 학생 아래만 받는다고 했기에 상위 클래스인 Person은 수용이 불가능하다.

            

//           WildExample.registerCourseWorker(personCource); // OK! Person worker의 상위타입이기에 가능하다!

            

       System.out.println("==========================================================================");

            

//     ================================================================================================================================

            

             Course<Worker> WorkerCourse = new Course<Worker>("직장인과정",5);

             WorkerCourse.add(new Worker("직장인")); // 모집인원 1

            

             WildExample.registerCourse(WorkerCourse);

             // 출력 : 직장인과정 수강생 : [Person(name=직장인), null, null, null, null]

            

//           WildExample.registerCourseStudent(WorkerCourse);

             // xx : Course<? extends Student>관련으로 예외가 발생하는데, 이는 학생이거나 학생을 자식으로 두어야 활용이 가능한데

             // Worker는 학생과 아무런 상관이 없기에 사용이 불가능 하다.

            

//           WildExample.registerCourseWorker(WorkerCourse); // OK! 직장인은 직장인을 포함하니 가능하다!

            

       System.out.println("==========================================================================");

            

//     ================================================================================================================================

            

             Course<Student> studentCourse = new Course<Student>("학생과정",5);

             studentCourse.add(new Student("학생"));

             studentCourse.add(new HighschoolStudent("고등학생"));

            

             WildExample.registerCourse(studentCourse);

             // 출력 : 학생과정 수강생 : [Person(name=학생), Person(name=고등학생), null, null, null]

            

//           WildExample.registerCourseStudent(studentCourse); // OK! 학생은 학생이기에 가능하다!

            

//           WildExample.registerCourseWorker(studentCourse); // xx : 최소한 직장이이거나 직장인의 상위 클래스여만 가능하다.

            

       System.out.println("==========================================================================");

            

//     ================================================================================================================================

            

             Course<HighschoolStudent> highStudentCourse = new Course<HighschoolStudent>("고등학생과정",5);

             highStudentCourse.add(new HighschoolStudent("고등학생"));

            

             WildExample.registerCourse(highStudentCourse);

             // 출력과정 : 고등학생과정 수강생 : [Person(name=고등학생), null, null, null, null]

            

//           WildExample.registerCourseStudent(highStudentCourse); // OK! 고등학생은 학생의 자식이기에 가능하다!

            

//           WildExample2.registerCourseWorker(highStudentCourse); // xx : 최소한 직장이이거나 직장인의 상위 클래스여만 가능하다.

             // 학생과 고등학생은 직장인과 아무런 관계를 맺고 있지 않다.

            

       System.out.println("==========================================================================");

            

//     ================================================================================================================================

            

             registerCourse(studentCourse);

             registerCourse(highStudentCourse);

             System.out.println();

            

             // 출력 :

//           학생과정 수강생 : [Person(name=학생), Person(name=고등학생), null, null, null]

//           고등학생과정 수강생 : [Person(name=고등학생), null, null, null, null]

            

//     ================================================================================================================================

            

       }// main

 

} // end class

 

10. 제한된 파라미터

 

package bounded_type;

 

public class Util {

      

       // 제네릭 정적 메소드 선언

       public static < T extends Number > int compare ( T t1, T t2 ) { // Number는 숫자 타입인 정수타입이나 실수타입 모두 가능하다.

            

             double v1 = t1.doubleValue();

             double v2 = t2.doubleValue();

            

//           Integer i = 100;

//           i.intValue();

//           i.doubleValue(); // 아니 integer는 정수타입인데 실수타입의 값도 가지고 있나??

             // 이는 Number에서 가지고 있는 정수와 실수를 다 T에 상속시켜줘서 예외가 발생하지 않는 것이다.

            

             return Double.compare(v1, v2);

            

       } // cpmpare

 

} // end class


package bounded_type;

 

public class BoundedTypeParameterExample { // 제한된 파라미터

      

       // 제한된 파라미터를 가진, 제네릭 메소드를 "사용할 때"

       // 구체타입으로 아무것이나 지정하지 못하고, 오로지 Number 타입 또는 그 자식의 타입만

       // 지정이 가능하다!

      

       public static void main (String[] args) {

            

             int result1 = Util.compare( 10, 20 ); // 1st. invoked generic method

            

             System.out.println(result1); // 출력 : -1

             // .compare은 단순히 대소비교를 하는 것이기에 정확한 차이를 보여주지는 않는다.

             // 음수값을 나타나기에 왼쪽 값이 오른쪽 값보다 크다는 것을 의미한다.

            

             int result3 = Util.<Double>compare(10.0, 20.123); // 실수를 비교하려면 안에 실수를 작성해줘야 한다.

            

//           =====================================================

            

             int result2 = Util.compare( 4.5, 3 ); // 2st. invoked generic method

             System.out.println(result2); // 출력 : 1

             // 양수값을 나타나기에 오른쪽 값이 왼쪽 값보다 크다는 것을 알 수 있다.

            

       } // main

      

       // 자바 표준 라이브러리에서 정렬등을 수행하기 위해서 (******)

       // 두 숫자( 정수이든 실수이든 )의 대소를 비교할 때, 아래와 같이 비교결과를 반환하도록 규칙화되어 있다. :

       // number1 , number2가 있다고 할 때,

       // if( number1 == number2 ) 이면 return 0을 한다!

       // if ( number1 < number2 ) 이면 return <음수값>을 한다! : 보통 -1을 반환한다.

       // if ( number1 > number2 ) 이면 return <양수값>을 한다! : 보통 +1을 반환한다.

 

} // end class

728x90
댓글
«   2024/09   »
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
최근에 올라온 글
Total
Today
Yesterday
공지사항