Chapter 1: Generics 개요
- Generics 개요
- 강력한 타입 검사
- 타입 변환 감소
- 알고리즘 일반화
Chapter 2: Generic 타입
- Generic 타입 선언
- Generic 타입 생성자
- Generic 객체 생성
Chapter 3: Generic 메소드
- Generic 메소드 선언
- 타입 추론
Chapter 4: 타입 파라미터
- 타입 파라미터 명명 규칙
- 다중 타입 파라미터
- 타입 제한
- 상속 및 서브 타입
- 와일드 카드
Chapter 5: 타입 삭제
- Generics 에서의 타입 삭제
- Generics 메소드에서의 타입 삭제
Chapter 6: Generics 제약
- 타입 파라미터 제약
- Generics 타입 제약
- 메소드 오버로딩 제약
Lab 11-A Generics를 이용한 응용 프로그램 작성
Chapter 1: Generics 개요
자바의 다형성 3가지
- 임의적인 다형성: 오버로딩 - 시그니처에 따라서 다르게 동작.
- 서브타입 다형성: 오버라이딩 - instance에 따라서 다르게 동작.
- 파라미터 다형성: Generics - 타입 매개변수를 사용하여 data type에 의존하지 않는 코드 작성.
Generics 개요
- 객체 생성시 부여되는 타입을 이용한 파라미터 다형성 구현.
- 타입(Class, Interface) 또는 메소드에 정의
class Box<T> {
T item;
public Box(T string) {
this.item = string;
}
public T getItem() {
return this.item;
}
}
Box<String> stringBox = new Box<>(“String”);
Box<Integer> integerBox = new Box<>(100);
class Box<T> {
T item;
public T simpleFunction(T item) { ... }
}
강력한 타입 검사
- Generics는 타입 안정성(Type Safety)을 지원(컴파일 타임에 검사함)
- java.lang.Object 타입으로 변환되는 객체 형 변환은 런타임에 검사. (컴파일시 오류 발견 불가)
- Generics는 타입이 명확히 명시되므로 컴파일 타임에 오류를 검출할 수 있음.
* Generics가 적용되지 않은 코드에서는 data를 최상위 타입인 java.lang.Object로 처리함
(컴파일 타임에 오류를 발견할 수 없다.)
public class TypeSafetyExample {
public static class Box {
Object item;
public void set(Object item) {
this.item = item;
}
public Object get() {
return this.item;
}
}
public static void main(String [] args) {
Box box = new Box();
box.set("Hello");
Integer value = (Integer) box.get(); // Object를 Integer로 형변환 하려고 해서 오류.
System.out.println("Value is " + value);
}
}
* Generics를 적용하면 컴파일 타임에 오류를 발견하여, 런타임 오류를 피할 수 있다.
public class TypeSafetyGenericsExample {
public static class Box<T> {
T item;
public void set(T item) {
this.item = item;
}
public T get() {
return this.item;
}
}
public static void main(String [] args) {
Box<String> box = new Box<>();
box.set("Hello");
Integer value = box.get();
System.out.println("Value is " + value);
}
}
// 컴파일러 오류
$ javac TypeSafetyGenericsExample.java
TypeSafetyGenericsExample.java:16: error: incompatible types: String cannot be converted to Integer
Integer value = box.get();
타입 변환 감소
- Super type을 Sub type으로 변환하기 위해서는 타입 변환이 필요.
- Generic을 적용하면 별도의 타입 변환 과정이 필요하지 않다.
/* Object(Super type) -> Integer(Sub type) 변환시 Type Casting이 필요. */
public class TypeSafetyExample {
public static class Box {
Object item;
…
}
public static void main(String [] args) {
…
Integer value = (Integer) box.get();
…
}
}
/* Generic은 별도의 Type Casting이 필요치 않다. */
public class TypeSafetyGenericsExample {
public static class Box<T> {
T item;
…
}
public static void main(String [] args) {
…
Integer value = box.get();
…
}
}
알고리즘 일반화
- Generics는 알고리즘 일반화를 구현할 수 있도록 한다.
- 다양한 타입의 객체들을 다루는 메소드나, 컬렉션 클래스에 컴파일 시 타입체크를 가능하도록 함.
- 타입 파라미터가 Comparable의 서브타입이면 정렬 가능하도록 정의
- 비교 가능한 아이템의 경우 정렬이 가능하도록 선언하며, 특정 데이터 타입에 국한되지 않는 일반적인 알고리즘 구현 가능.
2024.09.01 - [코딩 문제] - [코딩 문제] String Sort (with Bubble Sort)
[코딩 문제] String Sort (with Bubble Sort)
문제)Generic을 이용하여 String을 정렬해라. 코드import java.util.*;public class StringBubbleSort {// interface인 Comparable을 extends 하는 이유: T는 Comparable인 타입이어야 한다!! // 그래서 Comparable을 extends(확장)한
lightningtech.tistory.com
Chapter 2: Generic 타입
Generic 타입 선언
- 일반 타입 선언(Class, Interface)에 Type Parameter를 추가한 형태로 사용.
- Type Parameter는 Class나 Interface의 이름 뒤에 선언, <> 기호 사이에 열거. ex) <T>, <K, V>
- 하나 이상의 Type Parameter를 사용 가능.
/* Generic Type의 Class인 Box */
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return this.t;
}
}
/* 하나 이상의 Type Parameter 사용 가능 */
class Pair<K, V> {
private K key;
private V value;
public K getKey() {
return this. key;
}
public V getValue() {
return this. value;
}
}
Generic 타입 생성자
- Generic Type 생성자에서는 Type Parameter를 사용하지 않음.
- 일반 클래스와 동일한 방법으로 생성자 선언.
class Box<T> {
T box;
public Box(T box) {
this.box = box;
}
}
// 아래와 같은 방식으로 생성
Box<Integer> intBox = new Box<Integer>(1);
// 생성자 호출 시 타입 파라미터 타입 생략 가능.
Box<Integer> intBox2 = new Box<>(1);
Generic 객체 생성
- Generic 타입을 생성할 때 Type Parameter가 주어져야 함.
- 참조 변수와 생성자에 주어지는 Type Parameter는 동일해야 함.
- Type Parameter의 상속 관계는 Generic 타입 생성시 영향을 주지 않음.
- Type Parameter는 불공변성을 가짐.
- Generic 타입의 상속 관계는 일반 상속관계와 동일하게 적용됨.
- Type Parameter가 명확한 경우, 생서자 호출 시 전달되어야 하는 타입 변수는 생략 가능.
Box<Integer> box = new Box<Integer>();
Box<String> box = new Box<String>();
Box<Integer> box = new Box<>(1); // 생성자 호출시 전달되는 타입 변수 생략 가능.
Box<Integer> box = new Box<>("Hello"); // 컴파일 오류
Box<Integer> box = new Box("Hello"); // 오류 가능성 경고
Chapter 3: Generic 메소드
Generic 메소드 선언
- 일반 메소드 선언과 동일, 일반화 할 타입을 타입 파라미터로 선언.
- 메소드 앞에 <> 기호를 사용하여 타입 파라미터 목록을 선언.
- 타입 파라미터는 메소드의 return type 앞에 위치해야 한다.
<Access Modifier> <Type Parameter List> <Return Type> Method name(Parameter list)
/* 배열을 파라미터로 받아, 리스트로 반환. */
public class GenericMethod {
public static <T> List<T> arrayToList(T[] array) { // Generic method
List<T> list = new LinkedList<T>();
for(T t : array) {
list.add(t);
}
return list;
}
public static void main(String[] args) {
Integer[] array = {1, 2, 3};
GenericMethod me = new GenericMethod();
List<Integer> list = me.<Integer>arrayToList(array);
}
}
타입 추론
- 메소드 시그니처의 Type Parameter는 호출시 생략 가능.
- 컴파일러에서 주어진 Parameter를 통해 적용될 타입의 추론이 가능.
- 하나의 Type Parameter에 대해 추정되는 타입이 2개 이상 존재할 경우 오류 발생.
public <T> void fromArrayToCollection (T[] array, Collection<T> collection) {
...
}
String[] sa = new String[100];
Collection<String> cs = new ArrayList< >();
fromArrayToCollection(sa, cs); // T는 String으로 추론됨
Chapter 4: 타입 파라미터
타입 파라미터 명명 규칙
- E: 요소 (Element) - Java Collections Framewrok에서 폭 넓게 사용됨.
- K: 키(Key)
- N - 숫자(Number)
- T - 타입(Type)
- V - 값(Value)
- S, U, V 등 - 2번째, 3번째, 4번째 등
다중 타입 파라미터
- 파라미터에는 하나 이상의 타입을 지정할 수 있다.
public interface Pair<K, V> {
public K getKey();
public V getValue();
}
public class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}
- 다중 파라미터 타입도 타입 인자를 통해 타입 파라미터의 추론이 가능한 경우, 생성자에서 타입 인수의 생략이 가능함.
Pair<String, Integer> p1 = new OrderPair("Even", 8);
Pair<String, String> p2 = new OrderPair("Hello", "World");
타입 제한
- 타입 파라미터로 전달 가능한 함수는 참조 타입, 즉 클래스나 인터페이스로 제한됨.
- int, boolean 등 primitive data type을 사용해야 하는 경우 Wrapper 클래스를 사용.
Pair<String, int> p1 = new OrderedPair<String, int>("Even", 8); // 컴파일 오류
Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8); // 정상 동작
상속 및 서브 타입
- Type Parameter의 상속 관계는 Generic 타입의 상속과 무관함.
- Generic 파라미터로 지정된 타입 instance의 동작은 공변적이다.
/* Generic 파라미터로 전달되어 생성된 instance는 클래스의 타입 변환 규칙과 동일 */
Box<Number> box = new Box<Number>();
box.add(new Integer(10)); // OK
box.add(new Double(10.1)); // OK
- Type Parameter는 반공변적이다.
/* Generic 파라미터 타입과 생성자에서 생성되는 Generic 파라미터 타입은 반드시 같아야 한다. */
Box<Number> box = new Box<Integer>(); // 컴파일 오류, 별개의 타입으로 인식됨.
- Generic 클래스의 확장: Type Parameter를 변경하지 않는 한 서브 타입 지정 관계가 유지됨.
/* Generic 타입 상속 - 일반 클래스와 동일하게 확장 가능. */
public class Product<T, M> {
private T kind;
private M model;
public T getKind() {
return kind;
}
public void setKind(T kind) {
this.kind = kind;
}
public M getModel() {
return model;
}
public void setModel(M model) {
this.model = model;
}
}
public class ChildProduct<T, M, C> extends Product<T, M> {
private C company;
public C getCompany() {
return company;
}
public void setCompany(C company) {
this.company = company;
}
}
* Generic Type은 공변적이고, Generic Type Parameter는 불공변적이다.
// ArrayList는 List의 하위니까 가능 -> 타입은 공변적이다
List<Integer> list = new ArrayList<Integer>();
// List<Integer> list = new ArrayList<Short>();
// Short가 Integer의 하위여도 불가능 -> 타입 파라미터는 반 공변적이다.
와일드 카드
Generic을 정의할 때, return 값에 대한 특정한 타입 파라미터를 정의하지 않고 임의의 타입이 올 수 있는 기능을 제공한다. Generic 파라미터의 와일드 카드는 <?> 형식으로 정의되며, 인자로 받을 수 있는 타입의 제한이 가능하다.
- 파라미터나 return 값이 특정한 Type Parameter를 정의하지 않고, 임의의 타입을 지정.
- 타입 인자에 대한 제한을 두지 않음.
- 특정 타입 또는 상속 받은 타입으로 타입 인자를 제한
- 특정 타입 또는 상위 타입으로 타입 인자를 제한.
- 무제한 와일드 카드
- 타입 인자에 제한을 두지 않음.
void genericMethod(Collection<?> collection) { ... }
- 슈퍼 타입 제한 와일드 카드
- 지정된 타입이나 그로부터 상속 받은 타입에 한해서만 적용.
- 타입 파라미터에 extends 키워드를 사용해 허용가능한 최상위 타입을 선언.
void genericMethod(List<? extends Number>) { ... }
- 서브 타입 제한 와일드 카드
- 지정된 타입이나 슈퍼 타입에 한해서만 적용.
- 타입 파라미터에 super 키워드를 사용해 허용 가능한 최하위 타입을 선언.
void genericMethod(List<? super Number>) { ... }
class-programming_with_java/Module 11 Generics/contents/19_wildcard.adoc at master · gikpreet/class-programming_with_java
Contribute to gikpreet/class-programming_with_java development by creating an account on GitHub.
github.com
Chapter 5: 타입 삭제
Generics에서 Type Parameter는 컴파일 타임에만 사용되고, 컴파일 후에는 삭제 후 Object 타입으로 치환되어 byte code에는 Generic에 관한 정보가 저장되지 않는다.
Generics 에서의 타입 삭제
- Generic Type Parameter는 컴파일시에 모두 삭제됨.
- Type Parameter가 제한되지 않는 경우: Object Type으로 변경됨.
/* Generic Type Parameter */
public class Node<T> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
}
/* Object Type으로 변경됨 */
public class Node {
private Object data;
private Node next;
public Node(Object data, Node next) {
this.data = data;
this.next = next;
}
}
- 제한된 Type Parameter 사용하는 경우: 해당 타입으로 변경됨.
/* Generic Type Parameter, 그러나 제한됨 */
public class Node<T extends Comparable<T>> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
public T getData() {
return data;
}
}
/* 제한된 타입으로 대치 */
public class Node {
private Comparable data;
private Node next;
public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
}
public Comparable getData() {
return data;
}
}
Generics 메소드에서의 타입 삭제
- Generic 타입과 동일하게 Type Parameter는 삭제됨.
- 타입 제한이 없는 경우: Type Parameter는 Object 타입으로 변경됨.
/* Generic method의 Type Parameter */
public static <T> int count(T[] array, T element) {
int count = 0;
for (T e : array) {
if (e.equals(element)) {
++count;
}
}
return count;
}
/* 컴파일러가 Type Parameter를 Object로 대체 */
public static int count(Object[] array, Object element) {
int count = 0;
for (Object e : array) {
if (e.equals(element)) {
++count;
}
}
return count;
}
- 제한된 Type Parameter를 사용하는 경우: 해당 타입으로 변경됨
class Shape { ... }
class Circle extends Shape { ... }
class Rectangle extends Shape { ... }
public static <T extends Shape> void draw(T shape) { ... }
/* 컴파일시 draw Generic 메소드의 Type Parameter인 T를 Shape로 대치함 */
public static void draw(Shape shape) { ... }
Chapter 6: Generics 제약
타입 파라미터 제약
- Type Parameter 인자로 Primitive Data Type을 사용할 수 없음. (Wrapper class를 이용해야함)
- 컴파일 과정에서 Type Parameter 정보는 모두 삭제되고, Object 타입으로 처리됨.
- Type Parameter 변수의 객체를 생성할 수 없음.
- Type Parameter는 타입의 인자가 주어지기 전까지는 생성할 수 없다.
- static 필드로 선언될 수 없다.
- Type Parameter 인자가 달라질 수 있어, 특정 타입으로 생성할 수 없다.
Generics 타입 제약
- Generic 타입은 Type Casting 될 수 없으며, instanceof 연산자를 사용할 수 없다.
- Type Parameter는 컴파일시 모두 Object로 치환됨.
- 컴파일러에서는 Type Casting은 reference type의 경우, 상속 관계만 확인함.
- Type Parameter가 Object 타입으로 치환되어 instanceof로 구분이 어려움.
- Generic 타입의 배열은 생성할 수 없다. (리스트 사용해야 한다)
- Exception 타입의 서브 타입이 될 수 없다.
class-programming_with_java/Module 11 Generics/contents/25_generic_type_limitations.adoc at master · gikpreet/class-programming
Contribute to gikpreet/class-programming_with_java development by creating an account on GitHub.
github.com
메소드 오버로딩 제약
- Type Parameter만 다른 동일한 시그니처의 메소드는 존재할 수 없다.
(Type Parameter는 컴파일시 모두 Object로 치환됨)
/* Type Parameter가 다른 메소드 오버로딩 */
public class Example {
public void print(Set<String> set) { }
public void print(Set<Integer> set) { }
}
/* 위의 코드는 컴파일 후 아래와 같이 변경됨 */
public class Example {
public void print(Set<Object> set) { }
public void print(Set<Object> set) { }
}
2024.09.01 - [코딩 문제] - [코딩 문제] String Sort (with Bubble Sort)
[코딩 문제] String Sort (with Bubble Sort)
문제)Generic을 이용하여 String을 정렬해라. 코드import java.util.*;public class StringBubbleSort {// interface인 Comparable을 extends 하는 이유: T는 Comparable인 타입이어야 한다!! // 그래서 Comparable을 extends(확장)한
lightningtech.tistory.com
Lab 11-A Generics를 이용한 응용 프로그램 작성
'Java' 카테고리의 다른 글
[Java] 13. Anotation(어노테이션) (0) | 2024.09.02 |
---|---|
[Java] 12. Lambda Expression(람다식) (2) | 2024.09.01 |
[Java] Singleton 패턴 (0) | 2024.08.31 |
[Java] 10. Java에서의 상속 (0) | 2024.08.30 |
[Java] 09. 객체 생성과 제거 (0) | 2024.08.30 |