반응형
Generic
제네릭 타입은 컴파일 단계에서 잘못된 타입 사용될 수 있는 문제를 제거 할수있다.
컬렉션, 람다식(함수적 인터페이스), 스트림, Nio에서 널리사용
#제너릭을 모르면 api도큐먼트 해석이 어려우니 학습해야한다
제네릭의 이점은
컴파일 시 강한 타입 체크를 할수있다(완벽하게 타입을 체크)
- 실행 시 타입 에러가 나는 것 방지
- 컴파일 시에 미리 타입을 강하게 체크해서 에러 사전 방지
타입변환 제거 가능
제네릭 타입이란
타입을 파라미터로 가지는 클래스와 인터페이스
선언 시 클래스 또는 인터페이스 이름 뒤에 <> 부호를 붙인다
<> 사이에는 타입 파라미터 위치한다
타입 파라미터는 일반적으로 대문자 알파벳 한문자로 표현 …
개발 코드에서는 타입 파라미터 자리에 구체적인 타입을 지정해야함
제네릭 타입 사용여부에 따른 비교
제네릭 타입을 사용하지 않은 경우
Object 타입 사용 > 빈번한 타입 변환 발생 > 프로그램 성능저하.
제네릭 타입 사용한 경우
클래스 선언할 때 타입 파라미터 사용
컴파일 시 타입 파라미터가 구체적인 클래스 변경가능
제네릭 Ex)
public class ProductExample {
public static void main(String[] args) {
Product<Tv, String> product1 = new Product<Tv, String>();
product1.setKind(new Tv());
product1.setModel("스마트Tv");
Tv tv = product1.getKind();
String tvModel = product1.getModel();
// public class Product<Tv, String> {
// private Tv kind;
// private String model;
//
// public Tv getKind() { return this.kind; }
// public String getModel() { return this.model; }
//
// public void setKind(Tv kind) { this.kind = kind; }
// public void setModel(String model) { this.model = model; }
// }
Product<Car, String> product2 = new Product<Car, String>();
product2.setKind(new Car());
product2.setModel("디젤");
Car car = product2.getKind();
String carModel = product2.getModel();
// public class Product<Car, String> {
// private Car kind;
// private String model;
//
// public Car getKind() { return this.kind; }
// public String getModel() { return this.model; }
//
// public void setKind(Car kind) { this.kind = kind; }
// public void setModel(String model) { this.model = model; }
// }
}
}
public class ABox<T> {
private T t;
public T get(){ // get메소드 리턴
return t;
}
public void set(T t) {
this.t = t;
}
}
public class ABoxExample { // Generic 타입 기본.
public static void main(String[] args) {
ABox<String> box1 = new ABox<String>();
box1.set("Hi");
String str = box1.get();
ABox<Integer> box2 = new ABox<Integer>();
box2.set(5);
Integer value = box2.get();
}
}
멀티 타입 파라미터
제네릭 타입은 두 개 이상의 타입 파라미터 사용 가능
각 타입 파라미터 콤마로 구분
Ex) class<K, V, …> { } , interface <K, V, … > { }
자바 7부터는 다이아몬드 연산자 사용해 간단히 작성과 사용 가능
public class BTv {
}
public class BCar {
}
public class BProduct<T, M> {
private T kind;
private M model;
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;
}
}
public class BProductExample {
public static void main(String[] args) {
BProduct<BTv, String> product1 = new BProduct<BTv, String>();
product1.setKind(new BTv());
product1.setModel("스마트Tv");
BTv tv = product1.getKind();
String tvModel = product1.getModel();
BProduct<BCar, String> product2 = new BProduct<BCar, String>();
product2.setKind(new BCar());
product2.setModel("디젤");
BCar car = product2.getKind();
String carModel = product2.getModel();
}
}
제네릭 메소드
매개변수 타입과 리턴 타입으로 파라미터를 갖는 메소드
제네릭 메소드 선언 방법
- 리턴 타입 앞에 <> 기호를 추가하고 타입 파라미터 기술
- 타입 파라미터를 리턴 타입과 매개변수에 사용…
public class CBox<T> {
private T t;
public T get() {
return t;
}
public void set(T t) {
this.t = t;
}
}
public class CUtil {
public static <T> CBox<T> boxing(T t){
CBox<T> box = new CBox<T>();
box.set(t);
return box;
}
}
public class CBoxingMethodExample {
public static void main(String[] args) {
CBox<Integer> box1 = CUtil.<Integer>boxing(100);
int intValue = box1.get();
CBox<String> box2 = CUtil.boxing("길동이");
String setValue = box2.get();
}
}
타입 파라미터로 K와 V를 선언해서 메소드 두개의 값이 동일한지 비교하기.
public class DPair<K, V> {
private K key;
private V value;
public DPair(K key, V value){
this.key = key;
this.value = value;
}
public void setKey(K key) {
this.key = key;
}
public void value(V value) {
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
public class DUtil {
public static <K, V> boolean compare (DPair<K, V> p1, DPair<K, V> p2){
boolean keyCompare = p1.getKey().equals(p2.getKey());
boolean valueCompare = p1.getValue().equals(p2.getValue());
return keyCompare && valueCompare;
}
}
public class DCompareMethodExample {
public static void main(String[] args) {
DPair<Integer, String> p1 = new DPair<Integer, String>(1, "사과");
DPair<Integer, String> p2 = new DPair<Integer, String>(1, "사과");
boolean result1 = DUtil.compare(p1, p2); // <Integer, String>
if(result1) {
System.out.println("논리적으로 동등한 객체");
}else {
System.out.println("동등하지 않은 객체");
}
DPair<String, String> p3 = new DPair<String, String>("User1", "사과");
DPair<String, String> p4 = new DPair<String, String>("User2", "사과");
boolean result2 = DUtil.compare(p3, p4); // <Integer, String>
if(result2) {
System.out.println("논리적으로 동등한 객체");
}else {
System.out.println("동등하지 않은 객체");
}
}
}
제한된 타입 파라미터 <T extends 최상위 타입>
타입 파라미터에 지정되는 구체적인 타입 제한할 필요
- 상속 및 구현 관계 이용해 타입 제한
- 상위 타입은 클래스 뿐만 아니라 인터페이스도 가능
타입 파라미터를 대체할 구체적인 타입 - 상위 타입이거나 하위 또는 구현 클래스만 지정가능
public class EUtil {
public static <T extends Number> int compare(T t1, T t2) {
double v1 = t1.doubleValue();
double v2 = t2.doubleValue();
return Double.compare(v1, v2);
}
}
public class EBoundedTypeParameterExample {
public static void main(String[] args) {
int result1 = EUtil.compare(20,50);
System.out.println(result1);
int result2 = EUtil.compare(50, 3.5);
System.out.println(result2);
}
}
와일드카드 타입 (중ㅇ)
세가지 형태
- 제네릭타입 <?> Unbounded Wildcards(제한없음)
타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스나 인터페이스 타입이 올 수 있다.
-제네릭타입<? extends 상위타입> Upper Bounded Wildcards (상위 클래스 제한)
타입 파라미터를 대치하는 구체적인 타입으로 상위 타입이나 하위 타입만 올수 있다.
-제네릭타입<? super 하위타입> Lower Bounded Wildcards (하위 클래스 제한)
타입 파라미터를 대치하는 구체적인 타입으로 하위 타입이나 상위 타입이 올수 있다.
public class FCourese<T> {
private String name;
private T[] students;
public FCourese(String name, int capacity) {
this.name = name;
students = (T[]) (new Object[capacity]); // 타입 파라미터로 배열을 생성하려면 new T[n]형태로 배열을 생성할수 없구 , (T[]) (new Object[n])으로 생성해야 한다.
}
public String getName() {
return name;
}
public T[] getStudents() {
return students;
}
public void add(T t) { // 배열에 비어있는 부분을 찾아서 수강생을 추가하는 메소드.
for(int i=0; i<students.length; i++) { // i를 students.length 길이 만큼 반복하고
if(students[i] == null) { // students[i]가 null과 같다면
students[i] = t; // students[i]를 t에 저장
break;
}
}
}
}
public class FHighStudent extends FStudent {
public FHighStudent(String name) {
super(name);
}
}
public class FPerson {
private String name;
public FPerson(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String toString() {
return name;
}
}
public class FStudent extends FPerson {
public FStudent(String name) {
super(name);
}
}
public class FWorker extends FPerson {
public FWorker(String name) {
super(name);
}
}
import java.util.Arrays;
public class FWildCardExample {
public static void registerCourse(FCourese<?> coures) {
System.out.println(coures.getName() + " 수강생: " + Arrays.toString(coures.getStudents()));
}
public static void registerCourseStudent(FCourese<? extends FStudent> coures) {
System.out.println(coures.getName() + " 수강생: " + Arrays.toString(coures.getStudents()));
}
public static void registerCourseWorker(FCourese<? super FWorker> coures) {
System.out.println(coures.getName() + " 수강생: " + Arrays.toString(coures.getStudents()));
}
public static void main(String[] args) {
FCourese<FPerson> personCoures = new FCourese<FPerson>("일반인과정", 5);
personCoures.add(new FPerson("일반 "));
personCoures.add(new FWorker("직장 "));
personCoures.add(new FStudent("학생 "));
personCoures.add(new FHighStudent("고등학생"));
FCourese<FWorker> FworkerCourse = new FCourese<FWorker>("직장과정",5);
FworkerCourse.add(new FWorker("직장"));
FCourese<FStudent> FstudentCourse = new FCourese<FStudent>("학생과정", 5);
FstudentCourse.add(new FStudent("학생"));
FstudentCourse.add(new FHighStudent("고등학생"));
FCourese<FHighStudent> FhighStudentCourse = new FCourese<FHighStudent>("고등학생과정", 5);
FhighStudentCourse.add(new FHighStudent("고등학생"));
registerCourse(personCoures);
registerCourse(FworkerCourse);
registerCourse(FstudentCourse);
registerCourse(FhighStudentCourse);
System.out.println();
registerCourseStudent(FstudentCourse);
registerCourseStudent(FhighStudentCourse);
System.out.println();
registerCourseWorker(personCoures);
registerCourseWorker(FworkerCourse);
}
}
제네릭 타입을 부모 클래스로 사용할 경우
- 타입 파라미터는 자식 클래스에도 기술해야함
-추가적인 타입 파라미터를 가질수 있음.
제네릭 인터페이스를 구현할 경우 - 제네릭 인터페이스를 구현한 클래스도 제네릭 타입
제네릭 타입도 다른 타입과 마찬가지로 부모 클래스가 될수있다.
자식 제네릭 타입은 추가적으로 타입 파라미터를 가질수있다.
public interface GStorage<T>{
public void add(T item, int index);
public T get(int index);
}
public class GStoragelmpl<T> implements GStorage<T> {
private T[] array;
public GStoragelmpl(int capacity) {
this.array = (T[])(new Object[capacity]);
}
@Override
public void add(T item, int index) {
array[index] = item;
}
@Override
public T get(int index) {
return array[index];
}
}
public class GProduct<T,M> {
private T kind;
private M model;
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;
}
}
class Tv{
}
public class GChildProduct<T,M,C> extends GProduct<T,M> {
private C company;
public C getCompany() {
return this.company;
}
public void setCompany(C company) {
this.company = company;
}
}
public class GChildProductAndStorageExample {
public static void main(String[] args) {
GChildProduct<Tv, String, String> product = new GChildProduct<>();
product.setKind(new Tv());
product.setModel("SmartTV");
product.setCompany("Samsung");
GStorage<Tv> storage = new GStoragelmpl<Tv>(100);
storage.add(new Tv(), 0);
Tv tv = storage.get(0);
}
}
반응형
'Java > Java' 카테고리의 다른 글
Java Io기반 입출력 및 네트웤 #1 (0) | 2021.10.28 |
---|---|
자바[Java] 컬렉션 프레임워크(Collection Framework)에 대한 개념정리 (0) | 2021.10.25 |
Java 멀티스레드 (0) | 2021.10.22 |
Java 기본 API 클래스 #3 (0) | 2021.10.21 |
Java 기본API클래스 #2 (0) | 2021.10.20 |