반응형
제네릭 타입
- 타입파라미터는 원하는 만큼 <> 안에서 ,(콤마) 구분자로 여러개 선언할 수 있다
- 제네릭타입 객체 생성시 타입 파라미터 갯수만큼 타입을 넘겨 생성해야 한다
1)
public class D <K,V> {
public K field01;
public V field02;
public static void main(String[] args) {
D<String, Integer> d = new D<>();
d.field01 = "100"; //d 변수의 객체 생성시 첫번째 타입(String) field01 타입을 결정짓기 때문
d.field02 = 100; //d 변수의 객체 생성시 두번째 타입(Integer) field02 타입을 결정짓기 때문
D<Integer,String> dd = new D<>();
dd.field01 = 100;
dd.field02 = "100";
}
}
2) Product 제네릭 타입에 파라미터로 Car, TV 를 사용하여 실행
public class Product <K,M> {
private K kind;
private M model;
public K getKind() {
return kind;
}
public M getModel() {
return model;
}
public void setKind(K kind) {
this.kind = kind;
}
public void setModel(M model) {
this.model = model;
}
}
public class Car {
String car = "Car : ";
}
public class TV {
String tv = "TV : ";
}
public class GenericExample2 {
public static void main(String[] args) {
//K는 TV, M은 String으로 대체
Product<TV,String> p1 = new Product<>();
//Setter 매개값은 반드시 TV와 String을 제공
p1.setKind(new TV());
p1.setModel("스마트TV");
//Getter 리턴값은 TV와 String
TV tv = p1.getKind();
String tvModel = p1.getModel();
System.out.println(tv.tv + tvModel);
//K는 Car, M은 String으로 대체
Product<Car,String> p2 = new Product<>();
//Setter 매개값은 반드시 Car와 String을 제공
p2.setKind(new Car());
p2.setModel("SUV자동차");
//Getter 리턴값은 Car와 String
Car car = p2.getKind();
String carModel = p2.getModel();
System.out.println(car.car + carModel);
}
}
실행결과)
TV : 스마트TV Car : SUV자동차 |
3)
public class Container2<N,W> {
private N name;
private W work;
public void set(N name, W work) {
this.name = name;
this.work = work;
}
public N getKey() {
return name;
}
public W getValue() {
return work;
}
public static void main(String[] args) {
Container2<String,String> c1 = new Container2<>();
c1.set("홍길동", "도적");
String name1 = c1.getKey();
String job = c1.getValue();
System.out.println("이름 : " + name1 + ", 직업 : " + job);
Container2<String,Integer> c2 = new Container2<>();
c2.set("홍길동", 35);
String name2 = c2.getKey();
int age = c2.getValue();
System.out.println("이름 : " + name2 + ", 나이 : " + age);
}
}
4) 인터페이스에도 제네릭 가능
인터페이스에서 Object로 할 경우 java.lang.ClassCastException 발생
public interface PrintService {
Object print();
}
public class Print1 implements PrintService {
@Override
public Object print() {
return new Object();
}
public static void main(String[] args) {
PrintService ps;
ps = new Print1();
String resultStr = (String)ps.print(); //java.lang.ClassCastException 발생
}
}
제네릭을 사용하여 인터페이스 수정
public interface PrintService<T> {
T print();
}
타입파라미터로 String을 지정
인터페이스에서 타입파라미터를 사용하는 경우 구현 클래스에 정의한 인터페이스의 타입과
개발코드에서 선언한 인터페이스 타입변수의 제네릭 타입이 일치해야 한다
public class Print1 implements PrintService<String> {
@Override
public String print() {
return "Hi";
}
public static void main(String[] args) {
PrintService<String> ps;
ps = new Print1();
String resultStr = (String)ps.print();
System.out.println(resultStr);
}
}
실행결과)
Hi |
Integer를 타입파라미터로 사용
public class Print2 implements PrintService <Integer> {
@Override
public Integer print() {
return 100;
}
public static void main(String[] args) {
PrintService<Integer> ps = new Print2();
System.out.println(ps.print() + 100);
}
}
실행결과)
200 |
5) 인터페이스 제네릭
public interface Rentable<P> {
P rent();
}
public class Home {
public void turnOnLight() {
System.out.println("전등을 켭니다");
}
}
public class Car2 {
public void run() {
System.out.println("자동차가 달립니다.");
}
}
public class HomeAgency implements Rentable<Home> {
@Override
public Home rent() {
return new Home();
}
}
public class CarAgency implements Rentable<Car2> {
@Override
public Car2 rent() {
return new Car2();
}
}
public class GenericExample3 {
public static void main(String[] args) {
HomeAgency homeAgency = new HomeAgency();
Home home = homeAgency.rent();
home.turnOnLight();
CarAgency carAgency = new CarAgency();
Car2 car2 = carAgency.rent();
car2.run();
}
}
제네릭 메소드
- 메소드 내부에서 사용하는 타입을 객체 외부에서 메소드를 호출할 때 결정짓는 방법을 의미함
public class Print2 implements PrintService <Integer> {
@Override
public Integer print() {
return 100;
}
//제네릭 메소드
public <T> void print2(T t) {
System.out.println(t);
}
public static void main(String[] args) {
PrintService<Integer> ps = new Print2();
System.out.println(ps.print() + 100);
Print2 p2 = new Print2();
p2.<String>print2("");
p2.<Integer>print2(100);
}
}
실행결과)
200 100 |
제한된 타입 파라미터
- 타입파라미터 내부에 extends 키워드를 사용하게 되는 경우 키워드 오른쪽 타입부터 하위 자식타입까지만 허용하겠다
public class GrandMam {
}
public class Mam extends GrandMam {
}
public class Child extends Mam {
}
public class Example <T extends GrandMam> {
public T field;
public static void main(String[] args) {
/*
Example<String> e1 = new Example<>();
Example<Integer> e2 = new Example<>();
*/
Example<GrandMam> e3 = new Example<>();
Example<Mam> e4 = new Example<>();
Example<Child> e5 = new Example<>();
}
}
OtherPair는 오류가 되도록 만들기
public class Pair<K,V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
public class ChildPair<K,V> extends Pair<K,V> {
public ChildPair(K k, V v) {
super(k, v);
}
}
public class OtherPair<K,V> {
private K key;
private V value;
public OtherPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
public class Util {
public static <T extends Pair<String,Integer>> Integer getValue(T pair,String name){
if(pair.getKey().equals(name)) {
return pair.getValue();
}
return null;
}
public static void main(String[] args) {
Pair<String, Integer> pair = new Pair<>("홍길동",35);
Integer age = Util.getValue(pair,"홍길동");
System.out.println(age);
ChildPair<String,Integer> childPair = new ChildPair<>("홍삼원",20);
Integer childAge = Util.getValue(childPair, "홍삼순");
System.out.println(childAge);
//OtherPair는 오류가 되도록 만들기
/*
OtherPair<String,Integer> otherPair = new OtherPair<>("홍삼원",20);
Integer otherAge = Util.getValue(otherPair, "홍삼순");
System.out.println(otherAge);
*/
}
}
와일드카드 타입 매개변수
- 제네릭타입을 사용하는 클래스를 매개변수 타입으로 사용하는 경우 반드시 타입파라미터값을 고정해야하는데 이때 특정타입은 고정하지 않고 선언하는 방법
- <?> : 모든 타입 허용
- <? extends 타입> : 특정타입 하위까지만 허용
- <? super 타입> : 특정타입 상위까지만 허용
public class Example2 {
public static void method(Example<?> e) { // ? 모든 타입 허용
}
public static void methodExtends(Example<? extends Mam> e) {
//매개변수의 제네릭 타입을 특정타입 하위까지만 허용
}
public static void methodSuper(Example<? super Mam> e) {
//제네릭 매개변수의 타입을 특정타입 상위까지만 허용
}
public static void main(String[] args) {
method(new Example<String>());
method(new Example<Integer>());
method(new Example<GrandMam>());
method(new Example<Child>());
/*
methodExtends(new Example<String>());
methodExtends(new Example<Integer>());
methodExtends(new Example<GrandMam>());
*/
methodExtends(new Example<Mam>());
methodExtends(new Example<Child>());
/*
methodSuper(new Example<String>());
methodSuper(new Example<Integer>());
*/
methodSuper(new Example<GrandMam>());
methodSuper(new Example<Mam>());
//methodSuper(new Example<Child>());
}
}
반응형
'Java' 카테고리의 다른 글
[Java] ArrayList, List 연습 (0) | 2024.08.21 |
---|---|
[Java] 컬렉션 프레임워크 (0) | 2024.08.16 |
[Java] 제네릭 (0) | 2024.08.14 |
[Java] Date, SimpleDateFormat, Calendar (0) | 2024.08.13 |
[Java] toString(), StringBuilder, StringTokenizer, Math, Wrapper (0) | 2024.08.10 |