-
day25_1 - JAVA (자바, Generic)KIC/JAVA 2021. 7. 19. 14:24반응형
[제네릭 타입(Generic)]
-> '컴파일 단계'에서 '잘못된 타입이 사용될 수 있는 문제'를 제거 가능
-> 컬렉션, 람다식(함수적 인터페이스), 스트림, NIO에서 널리 사용
-> 제네릭을 모르면 API 도큐먼트 해석이 어려우므로 학습이 필요하다.
-> 일반적인 코드를 작성하고, 이 코드를 다양한 타입의 객체에 대하여 재사용하는 프로그래밍 기법이다.
-> 클래스에서 사용할 타입을 클래스 외부에서 설정하는 타입이다.
[제네릭을 사용하는 코드의 이점]
-> 컴파일 시 강한 타입 체크가 가능
-> 컴파일 시에 미리 타입을 강하게 체크해서 에러를 사전에 방지한다.
[ex]
package javaPro.java_generic; class MyClass01{ @Override public String toString() { return "MyClass01 문장 실행"; } } class Pool01 { private Object object; public void set(Object object) { this.object = object; } public Object get(){ return object; } } public class GenericEx01 { public static void main(String[] args) { Pool01 gen = new Pool01(); gen.set("그랜저"); // Object <------- String type String name = (String)gen.get(); // get() 으로 받아오는 타입이 Object 이므로 name에 저장할때 (String)으로 형변환 필요 System.out.println(name); gen.set(new MyClass01()); // Object <---------- MyClass type MyClass01 g = (MyClass01)gen.get(); // get() 으로 받아오느 타입은 이역시 object 이므로 g에 저장할 때 (MyClass01)타입으로 형변한 필요 //String g2 (String) gen.get(); //이 문장은 error System.out.println(g); // g에 저장된 MyClass01 메서드 실행 } }
[제네릭 타입]
-> 타입을 파라미터로 가지는 클래스와 인터페이스
=> 선언 시 클래스 또는 인터페이스 이름 뒤에 '<>' 부호를 붙인다.
-> '<>' 사이에는 타입 파라미터 위치
타입 파라미터
-> 일반적으로 대문자 알파벳 한 문자로 표현
-> 개발 코드에서는 타입 파라미터 자리에 구체적인 타입을 지정해야 한다.
[제네릭 타입을 사용하지 않은 경우]
-> Object 타입 사용 -> 빈번한 타입 변환 발생 -> 프로그램 성능 저하
-> 제네릭은 타입이 Box 오브젝트로 들어가기 전부터 미리 타입을 사용자가 지정해서 집어넣는 기능이다.
[제네릭 타입을 사용한 경우]
-> 클래스를 선언할 때 타입 파라미터를 사용
-> 컴파일 시 타입 파라미터가 구체적인 클래스로 변경된다.
package javaPro.java_generic; /* 제네릭을 이용 타입을 정하지 않고 class를 구현하는 방법이다 class의 멤버, 메소드 파라메터, 리턴 타입, 인터페이스의 타입을 실행시에 적용 할 수 있다 실행 사용시 제네릭 생략가능함 */ class Pool02<T> { private T t; public void set(T t) { this.t = t; } public T get(){ return t; } } public class GenericEx02 { public static void main(String[] args) { // 제네릭 클래스이기 때문에 <String>를 지정해줘야 error가 안난다. Pool02<String> p = new Pool02<String>(); p.set("hello"); System.out.println(p.get()); String str = p.get(); //이전 GenericEx1 코드와 다르게 (String) 형변환이 필요 없다. System.out.println(str); Pool02<Integer> p2 = new Pool02<Integer>(); p2.set(1); System.out.println(p2.get()); int value = p2.get(); System.out.println(value); } }
[제네릭 타입은 두 개 이상의 타입 파라미터를 사용 가능]
[ex]
package javaPro.java_generic; /* 제네릭 : <T, M> 은 모든 문자가 가능 하다. 주로 영문 대문자 한글자를 쓴다 *제네릭 class 구현 */ class Product<T, M> { private T kind; private M model; public T getKind() { return this.kind; } public void setKind(T kind) { this.kind = kind; } public M getModel() { return this.model; } public void setModel(M model) { this.model = model; } public String toString() { return "Product [kind =" + kind + ", model = " + model + "]"; } } class Car { public String toString() { return "Car"; } } class Tv { public String toString() { return "Tv"; } } public class GenericEx3 { public static void main(String[] args) { Product<Tv, String> product1 = new Product<Tv, String>(); product1.setKind(new Tv()); // 메소드를 매개변수로 받아 저장 product1.setModel("스마트Tv"); // String 을 매개변수로 받아 저장 Tv tv = product1.getKind(); // 리턴 값이 tv 메서드 String tvModel = product1.getModel(); // 리턴 값이 String System.out.println("Tv 메서드 결과값: " + tv + "\n" + "tvModel 변수 저장값: " + tvModel); System.out.println(product1); Product<Car, String> product2 = new Product<Car, String>(); product2.setKind(new Car()); product2.setModel("디젤"); Car car = product2.getKind(); String carModel = product2.getModel(); System.out.println("Car 메서드 결과값: " + car + "\n" + "carModel 변수 저장값: " + carModel); System.out.println(product2); } }
자바 7부터는 다이아몬드 연산자를 사용해 간단히 작성 가능
[제네릭 메소드]
-> 매개변수 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드
-> 제네릭 메소드 선언 방법
-> 리턴 타입 앞에 '<>' 기호를 추가하고 타입 파라미터를 기술
-> 타입 파라미터를 리턴 타입과 매개변수에 사용한다.
[ex]
package javaPro.java_generic; /* * 제네릭 Method구현 : class 이용 하지 않고 메소드만을 제네릭으로 구현한다 * 실행 사용시 제네릭 생략가능함 * * */ class Pool04<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } } // 다양 한 방식의 메소드들을 Generic으로 구현한 코드 class Util04 { public static <T> Pool04<T> staticMethod(T t) { Pool04<T> box = new Pool04<T>(); box.set(t); return box; } public <T> Pool04<T> instanceMethod1(T t) { Pool04<T> box = new Pool04<T>(); box.set(t); return box; } public <T> String instanceMethod2(T t) { return t.toString(); } } class MyCar { public String toString() { return "MyCar"; } } public class GenericEx4 { public static void main(String[] args) { Pool04<Integer> box1 = Util04.<Integer>staticMethod(100); // 제네릭 생략 가능 int intValue = box1.get(); System.out.println(intValue); Util04 u = new Util04(); // 제네릭을 생략했기 때문에 어떤 값이든 가능 Pool04<String> box2 = u.<String>instanceMethod1("홍길동"); // 생략 가능 String strValue = box2.get(); System.out.println(strValue); System.out.println(u.instanceMethod2(100)); // 정수 문자 메소드 다 잘 들어간다. System.out.println(u.instanceMethod2("김자바")); System.out.println(u.instanceMethod2(new MyCar())); } }
[제네릭 타입 제한하기]
package javaPro.java_generic; class Pool05<T extends Number> { // Number를 상속받은 타입으로만 제한하겠다는 의미 T v; Pool05(T n){ v = n; } void set(T n) { v = n; } T get() { return v; } } class Util05 { public static <T extends Number> int compare(T t1, T t2) { double v1 = t1.doubleValue(); // System.out.println(t1.getClass().getName()); double v2 = t2.doubleValue(); // System.out.println(t2.getClass().getName()); return Double.compare(v1, v2); // compare: 앞이 크면 1 출력 , 뒤가 크면 -1 출력 } } public class GenericEx5 { public static void main(String[] args) { // 제네릭 클래스는 <> 생략이 가능하다. //T는 Number를 상속받는 타입으로만 제한했기 때문에 String 타입은 error //String str = Util05.compare("a", "b"); int result1 = Util05.<Integer>compare(10, 20); System.out.println(result1); //1 출력 int result2 = Util05.compare(4.5, 3); System.out.println(result2); //-1 출력 Pool05<Integer> p1 = new Pool05<Integer>(20); Pool05<Double> p2 = new Pool05<Double>(20.0); //제네릭 에서 T는 Number를 상속받는 타입으로만 제한했기 때문에 String 타입과 Character은 error //Pool05<String> p3 = new Pool05<String>("hello"); //Pool05<Character> p4 = new Pool05<Character>('a'); Pool05<Byte> p5 = new Pool05<Byte>((byte) 1); int value = p1.get(); System.out.println(value); System.out.println(p2.get()); System.out.println(p5.get()); } }
[제네릭 타입 배열 입력]
package javaPro.java_generic; //제네릭 타입 배열 입력하기 구현 class Generic1<T> { T[] v; public T[] getV() { return this.v; } public void setV(T[] v) { this.v = v; } public void print() { for (T s : v) System.out.print(s + ","); System.out.println(); } } public class GenericEx7 { public static void main(String[] args) { Generic1<String> t = new Generic1<String>(); String[] ss = { " 월매 ", " 순향 ", " 향단 " }; t.setV(ss); t.print(); for (String s : t.getV()) System.out.println(s.trim()); Integer[] ii = { 10, 20, 30 }; // t.set(ii); // 지금 t는 String 타입이기 때문에 Integer 넣으면 오류 Generic1<Integer> t2 = new Generic1<Integer>(); t2.setV(ii); t2.print(); for (Integer s : t2.getV()) System.out.println(s / 10); } }
300x250'KIC > JAVA' 카테고리의 다른 글
day25_2 - JAVA (자바, Collection) (0) 2021.07.19 day25_2 - JAVA (자바, Collection) (0) 2021.07.19 day24 - JAVA (자바 , SimpleDateFormat, DecimalFormat, parse, Math, Calendar) (0) 2021.07.17 day23 - JAVA (자바 , JAVA API, java lang, equals(), 객체 해시코드, toString()) (0) 2021.07.17 day22 - JAVA (자바 , 접근 제한자, 예외 처리(Exception Handle)) (0) 2021.07.17