반응형
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
- pub.dev
- exception
- c
- Scaffold
- 디프만16기
- 부하 테스트
- java
- Sharding
- Kotlin
- 코드 트리
- 연습문제
- 운영체제
- 자료구조
- 코딩 테스트
- 코드트리
- dip
- AOP
- Spring
- nGrinder
- C언어
- Kafka
- depromeet
- Redis
- 디프만
- OAuth
- flutter
- kakao
- Oidc
- 코딩
- 코딩테스트
Archives
- Today
- Total
Nick Dev
[JAVA] About 제네릭 본문
반응형
김영한님의 '김영한의 실전 자바 - 중급 2편' 강의를 바탕으로 작성된 글입니다.
제네릭이란
타입 안정성을 위해서 사용
제네릭을 쓰면 코드 재사용 + 타입 안정성 모두 보장!!!
사용법
public class GenericBox<T> { -> 타입 매개변수
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
GenericBox<Integer> integerBox = new GenericBox<Integer>(); -> 타입 인자
T
: 타입 매개변수
추후에 Integer
, String
등 으로 변할 수 있음
- 타입이 맞지 않으면 컴파일 오류가 발생한다
핵심
- 제네릭의 핵심은 사용할 타입을 미리 결정하지 않는다는 점이다.
- 클래스 내부에서 사용하는 타입을 클래스를 정의하는시점에 결정하는 것이 아니라 실제 사용하는 생성 시점에 타입을 결정하는 것이다.
- 어떤 타입을 쓸지 미래로 미루는것
- 제네릭 클래스는 타입 매개변수에 타입 인자를 전달해서 사용할 타입을 결정한다.
제네릭 타입, 제네릭 클래스
- 클래스나 인터페이스를 정의할 때 타입 매개변수를 사용하는 것
public class GenericBox<T> { -> 타입 매개변수
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
GenericBox<T>
→ 제네릭 타입 이라고 함T
→ 타입 매개변수- 실제 타입으로 대체될 거임
GenericBox<Integer>
→ 제네릭 타입 사용할 때 제공되는 실제 타입Integer
→ 타입 인자
명명 관례
E - Element
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
제네릭 도입 한계
T의 타입을 메서드 작성 시점에 알 수 없다.
그래서
Object
기능만 사용 가능하다…public class AnimalHospitalV2<T> { private T animal; public void set(T animal) { this.animal = animal; } public void checkup() { // T의 타입을 메서드를 정의하는 시점에는 알 수 없다. Object의 기능만 사용 가능 animal.toString(); animal.equals(null); // 컴파일 오류 //System.out.println("동물 이름: " + animal.getName()); //animal.sound(); } public T getBigger(T target) { // 컴파일 오류 //return animal.getSize() > target.getSize() ? animal : target; return null; } }
그리고 우린 Animal 과 관련된 타입만 선언해서 사용하게 하고 싶음
오만가지 타입이 다 들어올 수 있음
public static void main(String[] args) { AnimalHospitalV2<Dog> dogHospital = new AnimalHospitalV2<>(); AnimalHospitalV2<Cat> catHospital = new AnimalHospitalV2<>(); AnimalHospitalV2<Integer> integerHospital = new AnimalHospitalV2<>(); AnimalHospitalV2<Object> objectHospital = new AnimalHospitalV2<>(); }
문제 1. 제네릭에서 타입 매개변수를 사용하면 어떤 타입이든 들어올 수 있다.
문제 2. 타입 매개변수를 어떤 타입이든 수용할 수 있는Object
로 가정하고,Object
의 기능만 사용할 수 있다.
타입 매개변수 제한
- 타입 매개변수를 특정 타입으로 제한
public class AnimalHospitalV3<T extends Animal> {
private T animal;
public void set(T animal) {
this.animal = animal;
}
public void checkup() {
System.out.println("동물 이름: " + animal.getName());
System.out.println("동물 크기: " + animal.getSize());
animal.sound();
}
public T getBigger(T target) {
return animal.getSize() > target.getSize() ? animal : target;
}
}
- T는 최소한
Animal
이다. - 그래서
Animal
의 기능들은 사용할 수 있다
문제 해결 1. 타입 안정성 문제 해결
문제 해결 2. 제네릭 도입 시, 어떤 타입이든 들어올 수 있던 문제 해결
- 제네릭에 타입 매개변수의 상한을 사용해서 타입 안전성을 지키면서 상위 타입의 원하는 기능까지 사용
제네릭 메서드와 와일드 카드
와일드 카드
static Animal printAndReturnWildcard(Box<? extends Animal> box) { Animal animal = box.get(); System.out.println("이름 = " + animal.getName()); return animal; }
제네릭 메서드
static <T extends Animal> T printAndReturnGeneric(Box<T> box) { T t = box.get(); System.out.println("이름 = " + t.getName()); return t; }
- 제네릭이니깐
Box<Dog> dogBox
가 들어오면T = Dog
이 되서 리턴 타입도Dog
이 된다
- 제네릭이니깐
둘 다 해결하는 건 비슷해 보임
하지만 리턴 타입이 다르다
와일드 카드는
Animal
로만 리턴되지만, 제네릭 메서드는 입력 받은 타입으로 리턴이 된다public static void main(String[] args) { Box<Object> objBox = new Box<>(); Box<Dog> dogBox = new Box<>(); Box<Cat> catBox = new Box<>(); dogBox.set(new Dog("멍멍이", 100)); Dog dog = WildcardEx.printAndReturnGeneric(dogBox); Animal animal = WildcardEx.printAndReturnWildcard(dogBox); }
- 제네릭 메서드는 매개변수로
dogBox
넣으니깐 리턴 타입이Dog
이 되는거고 - 와일드 카드는
Animal
로 리턴되는 차이가 있다
- 제네릭 메서드는 매개변수로
자바의 제네릭은 단순하게 생각하면 개발자가 직접 캐스팅 하는 코드를 컴파일러가 대신 처리해주는 것
타입 이레이저
컴파일 시점에서 제네릭 확인했으면 제네릭을 모두 지워버리고 타입 캐스팅만 해놓는다
기존 자바 코드와의 호환을 위해서
컴파일 전
public class AnimalHospitalV3<T extends Animal> { private T animal; public void set(T animal) { this.animal = animal; } public void checkup() { System.out.println("동물 이름: " + animal.getName()); System.out.println("동물 크기: " + animal.getSize()); animal.sound(); } public T getBigger(T target) { return animal.getSize() > target.getSize() ? animal : target; } }
컴파일 후
public class AnimalHospitalV3 { private Animal animal; public void set(Animal animal) { this.animal = animal; } public void checkup() { System.out.println("동물 이름: " + animal.getName()); System.out.println("동물 크기: " + animal.getSize()); animal.sound(); } public Animal getBigger(Animal target) { return animal.getSize() > target.getSize() ? animal : target; } } ---- AnimalHospitalV3 hospital = new AnimalHospitalV3(); ... Dog dog = (Dog) animalHospitalV3.getBigger(new Dog());
- 자바 컴파일러가 타입 인자로 지정한
Dog
로 캐스팅하는 코드 넣어줌
- 자바 컴파일러가 타입 인자로 지정한
컴파일 후에 제네릭을 다 없애거나 상한 타입으로 변경해버린다
- 컴파일 후에 제네릭 타입에 대한 정보 없음
반응형
'Java' 카테고리의 다른 글
[JAVA] CAS 알고리즘이란?! (0) | 2024.12.11 |
---|---|
[JAVA] volatile ⁉ (0) | 2024.12.11 |
[JAVA] Thread vs Process (0) | 2024.12.11 |
[JAVA] 객체 지향의 4대 특성 - 캡!상추다 (0) | 2024.12.11 |
[JAVA] HashMap의 내부 구현 방식 (0) | 2024.12.11 |