소위 제네릭: 클래스와 인터페이스를 정의할 때 유형 매개변수를 지정할 수 있습니다. 이 유형 매개변수는 변수를 선언하고 객체를 생성할 때 결정됩니다(즉, 유형 인수라고도 할 수 있는 실제 유형 매개변수를 전달합니다).
일반 클래스 또는 인터페이스
"다이아몬드" 구문 복사 코드는 다음과 같습니다.
//정의
공용 인터페이스 List<E>는 Collection<E>를 확장합니다.
공용 클래스 HashMap<K,V> 확장 AbstractMap<K,V> Map<K,V> 구현, 복제 가능, 직렬화 가능
//사용
List<String> 목록 = new ArrayList();
//Java 7 이후에는 뒤에 있는 꺾쇠괄호의 유형 매개변수를 생략할 수 있습니다.
List<String> list = new ArrayList<>();
일반 클래스에서 하위 클래스 파생
다음과 같이 코드 코드를 복사합니다.
//방법 1
공용 클래스 앱은 GenericType<String>을 확장합니다.
//방법 2
공용 클래스 App<T>는 GenericType<T>을 확장합니다.
//방법 3
공개 클래스 앱은 GenericType을 확장합니다.
의사 제네릭
실제 제네릭 클래스는 없습니다. 제네릭 클래스는 Java 가상 머신에 투명합니다. 즉, JVM은 제네릭 클래스를 일반 클래스와 다르게 처리하지 않습니다. 정적 메서드, 정적 초기화 블록 및 정적 변수에서.
- 아래 방법은 모두 잘못된 코드입니다.
개인 정적 T 데이터;
공전{
Tf;
}
공개 정적 무효 func(){
T 이름 = 1;
}
다음 예제에서는 일반 클래스가 없는지 확인할 수 있습니다. 코드는 다음과 같습니다.
공개 정적 무효 메인(문자열[] 인수){
List<String> a1 = new ArrayList<>();
List<Integer> a2 = new ArrayList<>();
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass());
System.out.println(a2.getClass());
}
출력 복사 코드는 다음과 같습니다.
진실
클래스 java.util.ArrayList
클래스 java.util.ArrayList
와일드카드 입력
우선, Foo가 Bar의 부모 클래스이지만 List<Foo>가 List<Bar>의 부모 클래스가 아닌 경우 Java는 다양한 일반 부모 클래스를 나타내기 위해 "?"를 사용한다는 점을 분명히 해야 합니다. 즉, List<?>는 다양한 일반 목록의 상위 클래스를 나타냅니다. 이러한 종류의 와일드카드를 사용하면 List 제네릭은 요소를 설정(설정)할 수 없지만 요소를 가져오는(가져오기)만 할 수 있습니다. 프로그램은 목록의 유형을 결정할 수 없기 때문에 개체를 추가할 수 없습니다. 그러나 얻은 객체는 Object 유형이어야 합니다.
다음 메서드는 오류와 함께 컴파일됩니다.
다음과 같이 코드 코드를 복사합니다.
List<?> list = new ArrayList<>();
list.add(새 객체());
몇 가지 아이디어:
1. List<String> 개체는 List<Object> 개체로 사용할 수 없습니다. 즉, List<String> 클래스는 List<Object> 클래스의 하위 클래스가 아닙니다.
2. 배열은 제네릭과 다릅니다. Foo가 Bar의 하위 유형(하위 클래스 또는 하위 인터페이스)이라고 가정하면 Foo[]는 여전히 Bar[]의 하위 유형이지만 G<Foo>는 G<Bar> 하위 유형이 아닙니다.
3. 다양한 일반 목록의 상위 클래스를 나타내려면 유형 와일드카드를 사용해야 합니다. 유형 와일드카드는 물음표(?)입니다. List 컬렉션에 유형 인수로 물음표를 전달합니다. >(알 수 없는 유형 요소 목록을 의미) 이 물음표(?)를 와일드카드 문자라고 하며 해당 요소 유형은 모든 유형과 일치할 수 있습니다.
와일드카드 상한
List<?extends SuperType>은 모든 SuperType 일반 목록의 상위 클래스 또는 자체를 나타냅니다. 와일드카드 상한이 있는 제네릭은 set 메소드를 가질 수 없으며 get 메소드만 가질 수 있습니다.
와일드카드의 상한을 설정하면 다음과 같은 문제를 해결할 수 있습니다. Dog는 Animal의 하위 클래스이며, 들어오는 목록 수를 가져오는 getSize 메서드가 있습니다. 코드는 다음과 같습니다.
추상 클래스 동물 {
공개 추상 무효 실행();
}
클래스 Dog 확장 동물 {
공개 무효 실행() {
System.out.println("개 달리기");
}
}
공개 수업 앱 {
공개 정적 무효 getSize(목록<동물> 목록) {
System.out.println(list.size());
}
공개 정적 무효 메인(String[] args) {
List<Dog> 목록 = new ArrayList<>();
getSize(list); // 여기서 컴파일 오류가 발생했습니다.
}
}
여기서 프로그래밍 오류가 발생하는 이유는 List<Animal>이 List<Dog>의 부모 클래스가 아니기 때문입니다. 첫 번째 해결책은 getSize 메소드의 형식 매개변수 List<Animal>을 List<?>로 변경하는 것인데, 이 경우 객체를 얻을 때마다 강제 유형 변환이 필요하므로 더 번거롭다. 와일드카드 상한을 사용하면 이 문제가 매우 잘 해결됩니다. List<Animal>을 List<?extends Animal>로 변경할 수 있으며 컴파일 시 오류가 없으며 유형 변환이 필요하지 않습니다.
와일드카드의 하한
List<? super SubType>은 SubType 일반 목록의 하한을 나타냅니다. 와일드카드 상한이 있는 제네릭은 get 메서드를 가질 수 없고 set 메서드만 가질 수 있습니다.
일반 메소드
유형 매개변수를 사용하지 않고 클래스와 인터페이스를 정의하지만 메소드를 정의할 때 유형 매개변수를 직접 정의하려는 경우 JDK1.5에서는 일반 메소드에 대한 지원도 제공합니다. 일반 메소드의 메소드 시그니처에는 일반 메소드의 메소드 시그니처보다 더 많은 유형 매개변수 선언이 있습니다. 유형 매개변수 선언은 꺾쇠괄호로 묶입니다. 모든 유형 매개변수 선언은 쉼표(,)로 구분됩니다. 수정자 및 메서드 반환 값 유형은 다음과 같습니다.
다음과 같이 코드 코드를 복사합니다.
수정자 반환 값 유형 메서드 이름(유형 목록) {
//메서드 본문
}
일반 메소드를 사용하면 유형 매개변수를 사용하여 메소드의 하나 이상의 매개변수 간 또는 메소드 반환 값과 매개변수 간의 유형 종속성을 표현할 수 있습니다. 이러한 유형 종속성이 없으면 일반 메서드를 사용하면 안 됩니다. 컬렉션의 복사 방법은 일반적인 방법을 사용합니다.
다음과 같이 코드 코드를 복사합니다.
공개 정적 <T> 무효 복사(목록<? 슈퍼 T> 대상, 목록<? 확장 T> src){ ...}
이 방법을 사용하려면 src 유형이 dest 유형 또는 그 자체의 하위 클래스여야 합니다.
삭제 및 변환
엄격한 제네릭 코드에서 제네릭 선언이 있는 클래스에는 항상 유형 매개변수가 있어야 합니다. 그러나 이전 Java 코드와 일관성을 유지하기 위해 유형 매개변수를 지정하지 않고 일반 선언이 있는 클래스를 사용할 수도 있습니다. 이 제네릭 클래스에 대해 유형 매개변수가 지정되지 않은 경우 유형 매개변수는 원시 유형이라고 하며 매개변수가 선언될 때 지정된 첫 번째 상한 유형이 기본값입니다.
일반 정보가 있는 객체가 일반 정보가 없는 다른 변수에 할당되면 꺾쇠 괄호 사이의 모든 유형 정보가 버려집니다. 예를 들어 List<String> 유형이 List로 변환되면 List의 컬렉션 요소에 대한 유형 확인이 유형 변수(즉, Object)의 상한이 되는 상황을 삭제라고 합니다.
샘플 복사 코드는 다음과 같습니다.
클래스 Apple<T 확장 번호>
{
T 사이즈;
퍼블릭애플()
{
}
공용 사과(T 사이즈)
{
this.size = 크기;
}
공공 무효 setSize(T 사이즈)
{
this.size = 크기;
}
공개 T getSize()
{
this.size를 반환합니다.
}
}
공개 클래스 ErasureTest
{
공개 정적 무효 메인(문자열[] 인수)
{
Apple<Integer> a = new Apple<>(6) // ①
// getSize 메소드는 Integer 객체를 반환합니다.
정수 = a.getSize();
// Apple 변수에 객체를 할당하면 꺾쇠 괄호 안의 유형 정보가 손실됩니다.
사과 b = a; // ②
// b는 크기 유형이 Number라는 것만 알고 있습니다.
숫자 size1 = b.getSize();
//다음 코드는 컴파일 오류를 발생시킵니다.
정수 size2 = b.getSize(); // ③
}
}