Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 마리아DB 쿼리 로그
- jquery
- interrupted()
- pseudo-code
- 구간합
- function test
- Java
- this와 this() 차이
- 2차원배열 구간합
- ajax
- 슈더코드
- 합배열
- 구간합구하기
- 생성자
- @AllArgsConstructor
- MariaDB Query Log
- 백준 11660번
- map()
- 백준 1235번
- select
- SQL
- 백준 11659번
- @NoArgsConstructor
- this
- InterruptException
- 자바 람다식
- Bean LifecCycle
- json
- 상속과 참조
- 백준
Archives
- Today
- Total
평범한 연구소
[JAVA] 제네릭 generic 본문
제네릭
- 다양한 타입의 객체 다루는 클래스나 인터페이스에서 사용할 데이터 타입을 인스턴스 생성 시 결정하는 것.
- 데이터 형에 대한 별도의 메소드나 멤버 변수를 구현할 필요 없이 미리 정의된 메소드 또는 멤버 변수에 서로 다른 자료 형으로 처리할 수 있다.
- 객체 타입을 컴파일 할 때 체크하므로 객체 타입의 안정성 높이고 불필요한 형 변환 줄임. (런타임오류 발생 확률 줄어든다)
- 객체 생성 시. 즉, 실행할 때 자료형이 결정됨
- 속도는 일반 자료형보다 느리지만, 안정성 높고 불필요한 형변환이 줄어듬.
- 반복적인 코드를 줄일 수 있으며, 재사용성 증가로 유지보수가 편리함.
- 엄격한 문법으로, 부모클래스도 허용X. =상속 허용X
제네릭 클래스 및 제네릭 인터페이스
- 타입 파라미터를 하나 이상 갖는 제네릭 타입의 클래스 또는 인터페이스
- 클래스나 인터페이스를 선언할 때 타입 지정하지 않고 인스턴스를 생성할 때 사용할 타입을 파라미터로 지정
- 클래스나 인터페이스를 선언할 때 클래스 또는 인터페이스 이름 뒤에 <> 부호 붙이고, <>부호 사이에 타입 파라미터 지정
- 제네릭은 두 개 이상의 타입 파라미터를 가질 수 있고, 각 타입은 콤마, 로 구분
타입 파라미터
- 대문자 알파벳 한 문자 사용
- E: Element
- K: Key
- N: Number
- T: Type
- V: Value
- S, U, V: 2nd, 3rd, 4th types
제한된 타입 파라미터
- 파라미터로 전달되는 타입의 종류 제한하는 기능
- extends 키워드로 사용
- ex) <타입파라미터 extends 상위클래스>
제네릭 메소드 호출 형식
- 1) 메소드 호출 형식
- 명시적으로 파라미터 지정
- ex) 리턴타입 변수 = 객체명.<명시적타입>메소드명(매개변수);
- 2) 매개변수값 타입으로 타입 파라미터 지정
- ex) 리턴타입 변수 = 객체명.메소드명(매개변수값);
제네릭 예제
- generic 타입을 명시하지 않으면 Object로 처리되고 오류는 아니나, 경고. 쓰지말 것
public class Ex03 {
public static void main(String[] args) {
Test3<String> t = new Test3<>();
t.setValue("서울");
String s = t.getValue(); // 캐스팅을 하지 않는다.
System.out.println(s+" : "+s.length());
// t.setValue(10); // 컴오류
Test3<Integer> t2 = new Test3<Integer>();
t2.setValue(30);
int n = t2.getValue();
System.out.println(n);
/*
Test3 t3 = new Test3(); // generic 타입 명시하지 않으면 Object으로 처리하며 경고!
t3.setValue(10);
t3.setValue("서울");
*/
}
}
class Test3<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
- getClass().getName(): 클래스의 이름을 문자열로 출력
- T: java.lang.String, U: java.lang.Integer
public class Ex04 {
public static void main(String[] args) {
Test4<String, Integer> t = new Test4<>();
t.set("서울", 950);
t.disp();
}
}
// 두 개의 타입 파라미터
class Test4<T, U> {
private T t;
private U u;
public void set(T t, U u) {
this.t = t;
this.u = u;
}
public void disp() {
System.out.println("T: "+t.getClass().getName() + ", "+t);
System.out.println("U: "+u.getClass().getName() + ", "+u);
}
}
- 제너릭은 일반적으로 다운캐스팅 하지 않는다. 배열과 같은 어쩔 수 없이 해야하는 상황이라면, 경고를 없애주기.
- @SuppressWarnings("unchecked"): 경고 없애기
- 어노테이션 관련 개념은 어노테이션 포스팅 참고.
@SuppressWarnings("unchecked")
public E get(int index) {
if(index >= count) {
throw new ArrayIndexOutOfBoundsException("없다");
}
return (E)data[index];
}
제네릭과 상속
- 제네릭 클래스에선 상속관계 성립X
- 타입 매개변수의 상속 관계는 성립O
- Number > Integer 에서, Integer은 Number를 상속 받음.
public class Ex01 {
public static void main(String[] args) {
Test1<Number> t1 = new Test1<>();
Integer i = 30;
t1.set(i); // 타입 매개변수의 상속 관계는 성립
// Number > Integer. Integer는 Number를 상속 받음.
Number n = t1.get();
System.out.println(n);
// Integer i2 = t1.get(); // 컴오류
Integer i2 = (Integer)t1.get();
System.out.println(i2);
// Number n2 = i; // up-casting. 가능
Test1<Integer> t2 = new Test1<>();
t2.set(10);
System.out.println(t2.get());
// Test1<Number> t3 = t2; // 컴파일오류. 제네릭은 상속 관계 안됨.
}
}
class Test1<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
제네릭의 와일드카드 <?>
- 제네릭은 컴파일 단계에서 타입 안정성을 위해 지원하므로, 다형성 갖지 않음
- 제네릭에 다형성 갖돌고 하기 위해선 와일드 카드를 사용
- 제네릭 타입 클래스를 파라미터로 사용할 때 구체적인 타입 정해지지 않는 경우에 사용
- 종류
- 제네릭타입<?> (비한정적 와일드카드)
- ?에는 모든 클래스나 인터페이스 타입 올 수 있음
- 제네릭타입<? extends 객체타입>
- 상위 클래스 제한
- ?에는 명시된 객체타입 또는 하위타입 가능
- 제네릭타입<? super 객체타입>
- 하위 클래스 제한
- ?에는 명시된 객체타입 또는 상위타입 가능
- 비한정적 와일드 카드 <?>
- 모든 클래스나 인터페이스 타입 가능 (아래의 경우 모두 가능)
- Object클래스의 기능 사용하여 구현할 수 있는 메소드 작성하는 경우
- 형식 매개 변수에 종속되지 않는 제네릭 클래스 메소드 사용하는 경우 (List의 size(),clear(),Class<T>의 대부분 메소드가 T에 의존하지 않으므로 Class<?> 로 자주 사용됨)
- List<Object> != List<?>
- Object 또는 Object의 하위 유형을 List<Object>에 삽입은 가능하나, List<?>는 null만 삽입 가능
- List<Object>는 String 객체 추가 가능
- 컴파일 시 형 안정성 보장X, 런타임에러 발생 가능성 있음
- List<?>는 컴파일 시 타입정보 알 수 없으므로 String 추가(add) 불가능하나, contains(Object o), remove(Object o) 같이 형인자 사용 않는 메소드는 그대로 사용 가능.
- 컴파일 시간에 형 안정성 보장하여 형인자에 대한 정보 없으므로 형인자 갖는 부분 제외한 메소드만 사용 가능
- 모든 클래스나 인터페이스 타입 가능 (아래의 경우 모두 가능)
public class Ex02 {
public static void main(String[] args) {
Test2<String> obj = new Test2<>();
obj.set("서울");
disp(obj);
System.out.println();
Test2<Integer> obj2 = new Test2<>();
obj2.set(950);
disp(obj2);
}
/*
제네릭타입<?>
: 제한 없음. 모든 클래스나 인터페이스가 가능
: 제네릭 타입에 의존적이지 않는 메소드등을 호출할 때 사용
: 읽기 전용으로 값을 변경할 수는 없음
*/
public static void disp(Test2<?> t) {
// t.set(20); // 컴오류. 자료형이 결정되지 않았으므로 값 바꿀 수 없음.
t.print();
}
}
class Test2<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public void print() {
System.out.println(t);
}
}
'JAVA > 기본 개념' 카테고리의 다른 글
[JAVA] Set - HashSet, LinkedHastSet, TreeSet (0) | 2022.08.06 |
---|---|
[JAVA] 리스트 List - ArrayList, LinkedList, Vector (0) | 2022.08.03 |
[JAVA] 인터페이스 (0) | 2022.07.27 |
[JAVA] 추상화 abstract (0) | 2022.07.27 |
[JAVA] 상속 | 오버라이딩 | 캐스팅 (0) | 2022.07.25 |