1. 자바 제네릭 소개
제네릭은 Java 1.5의 새로운 기능입니다. 제네릭의 본질은 매개변수화된 유형입니다. 즉, 연산되는 데이터 유형이 매개변수로 지정됩니다. 이 매개변수 유형은 각각 일반 클래스, 일반 인터페이스 및 일반 메소드라고 하는 클래스, 인터페이스 및 메소드 작성에 사용될 수 있습니다.
이번에 소개되는 Java 제네릭의 장점은 안전하고 간편하다는 것입니다.
Java SE 1.5 이전에는 제네릭이 없을 때 "임의" 매개변수가 Object 유형을 참조하여 구현되었습니다. "임의"의 단점은 명시적인 강제 변환이 필요하다는 점이었습니다. 개발자는 실제 매개변수 유형을 미리 알아야 합니다. 강제 유형 변환 오류의 경우 컴파일러에서 오류 메시지를 표시하지 않을 수 있으며 런타임 중에 예외가 발생합니다. 이는 보안상 위험합니다.
제네릭의 장점은 컴파일 중에 유형 안전성을 확인하고 모든 캐스트가 자동으로 암시적으로 수행되어 코드 재사용이 향상된다는 것입니다.
제네릭 사용에는 몇 가지 규칙과 제한 사항이 있습니다.
1. 제네릭의 유형 매개변수는 클래스 유형(사용자 정의 클래스 포함)만 가능하며, 간단한 유형.
2. 동일한 제네릭 유형이 여러 버전에 해당할 수 있으며(매개변수 유형이 불확실하기 때문에) 제네릭 클래스 인스턴스의 다른 버전은 호환되지 않습니다.
3. 제네릭은 여러 유형 매개변수를 가질 수 있습니다.
4. 예를 들어 일반 매개변수 유형은 확장 문을 사용할 수 있습니다. 관례적으로 "제한된 유형"이 됩니다.
5. 일반 매개변수 유형은 와일드카드 유형일 수도 있습니다.
Class<?> classType = Class.forName(java.lang.String);
제네릭에도 인터페이스, 메소드 등이 있습니다. 내용이 많고, 이를 능숙하게 이해하고 적용하려면 많은 노력이 필요합니다.
2. Java 제네릭 구현 원칙: 유형 삭제
Java의 제네릭은 의사 제네릭입니다. 컴파일하는 동안 모든 일반 정보가 지워집니다. 제네릭의 개념을 올바르게 이해하기 위한 첫 번째 전제 조건은 유형 삭제를 이해하는 것입니다.
Java의 제네릭은 기본적으로 컴파일러 수준에서 구현됩니다. 제네릭의 유형 정보는 생성된 Java 바이트코드에 포함되지 않습니다. 제네릭을 사용할 때 추가된 유형 매개변수는 컴파일 중에 컴파일러에 의해 제거됩니다. 이 프로세스를 유형 삭제라고 합니다.
코드에 정의된 List
3. 유형 삭제 후에도 유지되는 원본 유형
원본 유형(원시 유형)은 일반 정보가 삭제된 후 바이트코드에 있는 유형 변수의 실제 유형입니다. 제네릭 유형이 정의될 때마다 해당 기본 유형이 자동으로 제공됩니다. 유형 변수는 지워지고(crased) 정규화된 유형으로 대체됩니다(한정되지 않은 변수는 Object임).
class Pair<T> { private T value; public T getValue() { return value; } public void setValue(T value) { this.value = value; } }
pair
class Pair { private Object value; public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } }
pair
유형 변수가 경계형인 경우 원래 유형은 첫 번째 경계 유형 변수로 대체됩니다.
예를 들어, pair가 다음과 같이 선언된 경우:
public class Pair<T extends Comparable& Serializable> {
원래 유형은 Comparable입니다
참고:
pair가 이 클래스와 같이 공개로 선언된 경우, 원래 유형은 직렬화 가능으로 대체되고 컴파일러는 필요할 때 Comparable에 캐스트를 삽입합니다. 효율성을 위해 태그가 지정된 인터페이스(즉, 메서드가 없는 인터페이스)는 경계 한정 목록의 끝에 배치되어야 합니다.
기본 유형과 일반 변수 유형을 구별하려면
제네릭 메소드를 호출할 때 제네릭 유형을 지정할지 여부를 지정할 수 있습니다.
제네릭을 지정하지 않으면 제네릭 변수의 유형은 Object까지 메소드의 여러 유형 중 동일한 상위 클래스의 가장 낮은 수준입니다.
제네릭을 지정할 때 메서드의 여러 유형은 제네릭 인스턴스 유형이거나 해당 하위 클래스여야 합니다.
public class Test{ public static void main(String[] args) { /**不指定泛型的时候*/ int i=Test.add(1, 2); //这两个参数都是Integer,所以T为Integer类型 Number f=Test.add(1, 1.2);//这两个参数一个是Integer,以风格是Float,所以取同一父类的最小级,为Number Object o=Test.add(1, "asd");//这两个参数一个是Integer,以风格是Float,所以取同一父类的最小级,为Object /**指定泛型的时候*/ int a=Test.<Integer>add(1, 2);//指定了Integer,所以只能为Integer类型或者其子类 int b=Test.<Integer>add(1, 2.2);//编译错误,指定了Integer,不能为Float Number c=Test.<Number>add(1, 2.2); //指定为Number,所以可以为Integer和Float } //这是一个简单的泛型方法 public static <T> T add(T x,T y){ return y; } }
사실 제네릭 클래스에서는 제네릭 타입을 지정하지 않은 경우에는 이때 제네릭 타입이 Object라는 점만 빼면 거의 동일합니다. 예를 들어 ArrayList의 경우 일반 유형이 지정되지 않은 경우 모든 유형의 객체를 ArrayList에 배치할 수 있습니다.
4. C++ 템플릿 구현
C++는 모르지만 인터넷에서 C++ 구현을 찾아보기도 했습니다.
C++에서 템플릿의 각 인스턴스화에 대해 서로 다른 유형을 생성하는 것은 "템플릿 코드 팽창"이라고 알려진 현상입니다.
예를 들어 벡터
Java 제네릭의 구현 원리와 관련된 더 많은 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!