728x90
📌 제네릭(Generic)
- 제네릭이란 클래스나 메서드를 작성할 때, 타입을 구체적으로 지정하지 않고 추후에 지정하고 변경할 수 있도록 타입 매개변수를 이용하여 타입을 일반화하는 것을 의미한다.
제네릭 클래스
class Box<T> {
private T item1; // O
static T item2; // X
}
public class Main {
public static void main(String[] args) {
Box<String> Box1 = new Box<>("this is Box");
Box<Integer> Box2 = new Box<>(1);
Box<Double> Box3 = new Box<>(1.11);
// 제네릭 클래스로 인스턴스화할 때에는 타입 매개변수에 치환될 타입을 지정해주어야 한다.
System.out.println(Box1.getItem());
System.out.println(Box2.getItem());
System.out.println(Box3.getItem());
}
}
class Box<T> { // T를 임의의 타입으로 사용한다. 여러개의 타입을 사용할 때는 <K, V> 등으로 사용할 수 있다.
private T item; // T : type, K : key, V : value의 첫글자를 따 만든 변수명
public Box(T item) {
this.item = item;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
// 출력값
this is Box
1
1.11
- 제네릭 클래스에서 클래스 변수에는 타입 매개변수를 사용할 수 없다. 클래스 변수는 모든 인스턴스가 공유하기 때문에 타입 매개변수를 사용한다면 클래스 변수의 타입이 서로 달라지게 되어 같은 변수를 공유하는 것이 아니게 되기 때문이다. 예를 들어 Box라는 클래스 변수에 타입 매개변수를 사용할 수 있다면, Box<String>으로 만든 인스턴스와 Box<Integer>로 만든 인스턴스가 공유하는 클래스 변수의 타입이 서로 달라진다.
interface Animal{}
class Dog implements Animal{} // (1)
class Siba extends Dog implements Animal{}; // (2)
class Example1 <T extends Dog> {
// Example1 클래스를 인스턴스화할 때 타입으로 Dog클래스의 하위 클래스만 지정하도록 제한
private T item;
}
class Example2 <T extends Animal> {
// Example2 클래스를 인스턴스화할 때 타입으로 Animal 인터페이스를 구현한 클래스만 지정하도록 제한
private T item;
}
class Example3 <T extends Dog & Animal> {
// Example 클래스를 인스턴스화할 때 타입으로 특정 클래스를 상속받으면서 동시에 특정 인터페이스를 구현한 클래스만 지정하도록 제한
private T item;
}
public class Main {
public static void main(String[] args) {
Example2<Dog> DogEx = new Example2<>(); // (1)
Example3<Siba> SibaEx = new Example3<>(); //(2)
}
}
- 특정 클래스를 상속받은 클래스나 특정 인터페이스를 구현한 클래스만 타입으로 지정할 수도 있다.
제네릭 메서드
class Box<T> { // (1)
public <T> void add(T element) { // (2) (1)의 T와 (2)의 T는 서로 다른 변수이다.
// 제네릭 메서드의 타입 매개변수 선언은 반환타입 void 앞에서 이루어지며, 해당 매서드 내에서만 사용할 수 있다.
}
}
클래스 전체를 제네릭으로 선언하는 것이 아닌 클래스 내부의 특정 메서드만 제네릭으로 선언하는 경우이다.
📌 와일드 카드
- 어떠한 타입으로든 대체될 수 있는 타입 파라미터이며 기호 '?'를 사용한다.
- 와일드 카드는 Any Type이 아니라, Unknown Type이다.
<? extends T>는 상한 제한을 두는 것으로, T와 T를 상속받는 하위 클래스 타입만 타입 파라미터로 받는다.
<? super T>는 하한 제한을 두는 것으로, T와 T의 상위 클래스만 타입 파라미터로 받는다.
<?>는 모든 클래스 타입을 타입 파라미터로 받을 수 있다.
class Laptop {}
class Windows extends Laptop {}
class Macbook extends Laptop {}
class Gram extends Windows{}
class Galaxybook extends Windows{}
class M1MacbookAir extends Macbook{}
class M2MacbookAir extends Macbook{}
class User<T> {
public T laptop;
public User(T laptop) {
this.laptop = User.this.laptop;
}
}
class LaptopFunction {
public static void Internet(User <? extends Laptop> user){
System.out.println("-".repeat(30));
System.out.println("user.laptop = " + user.laptop.getClass().getSimpleName());
System.out.println("모든 Laptop은 인터넷이 가능합니다.");
}public static void facetime(User <? extends Macbook> user){
System.out.println("-".repeat(30));
System.out.println("user.laptop = " + user.laptop.getClass().getSimpleName());
System.out.println("모든 Mac은 페이스타임이 가능합니다.");
}public static void macsafe(User <? extends M2MacbookAir> user){
System.out.println("-".repeat(30));
System.out.println("user.laptop = " + user.laptop.getClass().getSimpleName());
System.out.println("M2칩이 탑재된 맥북에어는 맥세이프로 충전이 가능합니다.");
}public static void game(User <? super Windows> user){
System.out.println("-".repeat(30));
System.out.println("user.laptop = " + user.laptop.getClass().getSimpleName());
System.out.println("윈도우 운영체제를 가진 게이밍 노트북은 원활한 게임 플레이가 가능합니다.");
}
}
public class Main {
public static void main(String[] args) {
LaptopFunction.Internet(new User<Laptop>(new Laptop()));
LaptopFunction.Internet(new User<Windows>(new Windows()));
LaptopFunction.Internet(new User<Macbook>(new Macbook()));
LaptopFunction.Internet(new User<Gram>(new Gram()));
LaptopFunction.Internet(new User<Galaxybook>(new Galaxybook()));
LaptopFunction.Internet(new User<M1MacbookAir>(new M1MacbookAir()));
LaptopFunction.Internet(new User<M2MacbookAir>(new M2MacbookAir()));
LaptopFunction.facetime(new User<Laptop>(new Laptop())); // 에러
LaptopFunction.facetime(new User<Windows>(new Windows())); // 에러
LaptopFunction.facetime(new User<Macbook>(new Macbook()));
LaptopFunction.facetime(new User<Gram>(new Gram())); // 에러
LaptopFunction.facetime(new User<Galaxybook>(new Galaxybook())); // 에러
LaptopFunction.facetime(new User<M1MacbookAir>(new M1MacbookAir()));
LaptopFunction.facetime(new User<M2MacbookAir>(new M2MacbookAir()));
LaptopFunction.macsafe(new User<Laptop>(new Laptop())); // 에러
LaptopFunction.macsafe(new User<Windows>(new Windows())); // 에러
LaptopFunction.macsafe(new User<Macbook>(new Macbook())); // 에러
LaptopFunction.macsafe(new User<Gram>(new Gram())); // 에러
LaptopFunction.macsafe(new User<Galaxybook>(new Galaxybook())); // 에러
LaptopFunction.macsafe(new User<M1MacbookAir>(new M1MacbookAir())); // 에러
LaptopFunction.macsafe(new User<M2MacbookAir>(new M2MacbookAir()));
LaptopFunction.game(new User<Laptop>(new Laptop()));
LaptopFunction.game(new User<Windows>(new Windows()));
LaptopFunction.game(new User<Macbook>(new Macbook())); // 에러
LaptopFunction.game(new User<Gram>(new Gram())); // 에러
LaptopFunction.game(new User<Galaxybook>(new Galaxybook())); // 에러
LaptopFunction.game(new User<M1MacbookAir>(new M1MacbookAir())); // 에러
LaptopFunction.game(new User<M2MacbookAir>(new M2MacbookAir())); // 에러
}
}
728x90
'[JAVA] > JAVA 기본' 카테고리의 다른 글
[JAVA] 컬렉션 프레임워크 (0) | 2022.09.14 |
---|---|
[JAVA] 예외 처리 정리 (0) | 2022.09.14 |
[JAVA] 열거형 (0) | 2022.09.13 |
[JAVA] 래퍼 클래스(Wrapper Class) (0) | 2022.09.13 |
[JAVA] 형변환 총정리 (0) | 2022.09.12 |