티스토리 뷰
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
'KH 정보교육원 [ Java ]' 카테고리의 다른 글
KH 21일차 - 함수적 인터페이스 및 컬렉션 프레임 워크 (0) | 2022.03.28 |
---|---|
KH 20일차 - 람다식과 함수적 인터페이 (0) | 2022.03.26 |
KH 18일차 - 예외처리코드 및 제네릭 (0) | 2022.03.24 |
KH 17일차 - 인터페이스와 예외처리 (0) | 2022.03.22 |
KH 16일차 - 추상 클래스 및 인터페이스 (0) | 2022.03.21 |