>  기사  >  Java  >  제네릭 사용 및 리플렉션 요약 - 제네릭

제네릭 사용 및 리플렉션 요약 - 제네릭

高洛峰
高洛峰원래의
2016-12-19 15:39:001608검색

제 생각에는 JDK5.0은 확실히 매우 획기적인 버전입니다. 이 버전에서는 Generics가 많이 제공되고 반사 메커니즘이 개선되었습니다. 5.0은 또한 이전 컬렉션 프레임워크를 재구성하고 일반 지원을 추가했습니다.
5.0이 출시된 지 거의 10년이 지났습니다. 온라인과 책에서도 이 부분에 대한 지식이 많이 있습니다. 엘리펀트는 첫째로 자신의 경험과 경험을 요약하기 위해 이 글을 쓰고 있으며, 둘째로 이 측면을 처음 접하는 아이들에게 도움이 되기를 바라는 마음에서 이 글을 쓰고 있습니다.
제네릭의 가장 큰 이점은 유형 검사입니다. 이는 특히 컬렉션에 유용하며 재사용이 가능하므로 기본 코드 설계에도 매우 유용합니다. 제네릭을 정의하는 방법에는 두 가지가 있습니다. 하나는 제네릭 클래스이고 다른 하나는 제네릭 메서드입니다.
그렇다면 제네릭이란 정확히 무엇입니까? 간단히 말하면(엄밀하게는 아닐 수도 있지만) 클래스든, 인터페이스든, 메서드든 타입 매개변수 등의 타입 변수를 사용한다는 뜻이다. 예를 참조하세요:
일반 클래스
public class Person {
private T t;
public T getT() {
} return t;
}
public void setT(T t) {
This.t = t;
}
}
T는 유형 변수로 매개변수화된 유형이며 꺾쇠 괄호()로 묶여 있습니다. 클래스 이름 뒤에 옵니다. 일반 클래스에는 여러 유형 변수가 정의될 ​​수 있습니다. 유형 변수는 일반적으로 이 예에서는 Person, JDK에서는 List, Map 등과 같이 대문자로 표시됩니다.
유형 변수를 구체적인 클래스로 대체하여 일반 클래스를 인스턴스화하는 것이 가능합니다. Person person = new Person();
다음과 같이 인스턴스화하는 것은 잘못되었습니다. Person ; person = new Person
일반 메소드

public T get(String key, Object params) {
return (T) getSqlSession() .selectOne(key, params);
}

이것은 SSM3 예제의 MyBatisDao 클래스에 정의한 메서드입니다. 이 메서드는 일반적인 메서드입니다. 는 유형 변수이고, get 앞의 T는 반환 유형입니다. 실제로 이 메소드에는 유형 안전성 문제가 있습니다. RoleService에서 이 메소드를 호출하고 반환 유형 T를 User로 작성하면 컴파일러는 경고 메시지를 표시하지 않습니다.
하지만 다시 작성하고 MyBatisDao에 제네릭을 추가하면 공개 클래스 MyBatisDao가 SqlSessionDaoSupport를 확장합니다.
그러면 사용자 반환 유형에 컴파일 오류가 발생합니다:

제네릭 사용 및 리플렉션 요약 - 제네릭

Role 유형 변수 MyBatisDao를 기반으로 컴파일러는 여기에 정의된 get 메소드가 Role 유형을 반환해야 한다고 추론합니다. 그러나 이 변경 후 MyBatisDao는 일반 클래스가 되며 get 메소드는 더 이상 일반 메소드가 아닙니다. 그렇다면 일반 메서드에 안전 검사가 포함될 수 있나요? 예, 그러나 약간의 프로그래밍 기술이 필요합니다. 핵심은 나중에 언급되는 유형 매개변수에 대한 제한 사항과 관련되어 있으며 제네릭을 제한하고 일부 보안 검사 문제를 해결할 수 있습니다.
타입 매개변수 제한
와 같은 타입 변수가 표현하는 범위가 너무 커서 사용하기 불편할 때도 있습니다. 예를 들어, 이제 java.io.Serialized 인터페이스를 구현하는 일반 클래스를 구현해야 하는데 어떻게 해야 할까요? JDK 전문가들은 이 문제를 해결하기 위해 "제한된 와일드카드 유형"이라는 것을 설계했습니다. 일반적으로 상한과 하한이라고 부릅니다.
상한:
하한:
물음표(?) 무제한 와일드카드라고 하며 어떤 유형이든 나타낼 수 있습니다. 때로는 유형 변수를 사용하는 것이 그다지 편리하지 않은 경우가 있는데, 와일드카드 유형은 이 문제를 매우 잘 해결합니다.
는 T가 직렬화 가능 인터페이스를 구현하는 클래스이고, T가 바인딩 유형(Serialized)의 하위 유형이며, T와 바인딩 유형이 인터페이스 또는 클래스일 수 있음을 의미합니다. Comparable 인터페이스를 구현하는 제한 사항을 추가하려면 다음과 같이 작성하기만 하면 됩니다. Comparable 인터페이스는 일반 매개변수를 받을 수 있는 일반 인터페이스이기 때문에 이 작성은 약간 느슨합니다. .지금은 이에 대해 논의하지 않겠습니다.
super T> 모든 T 유형 변수의 슈퍼 유형에는 T 자체도 포함되는 것으로 이해될 수 있습니다. 왜냐하면 T는 그 자체의 슈퍼 유형으로 간주될 수 있기 때문입니다.
그럼 왜 연장이 상한이고 연장이 하한이라고 하는 걸까요? 직렬화 가능을 확장하거나 T를 확장하는 것은 이전 두 설명에서 분명해야 합니다. 이는 유형 변수가 직렬화 가능의 하위 클래스이고 T 변수의 하위 유형이어야 함을 나타냅니다. 이는 유형 변수의 상한을 제한하는 것과 동일합니까? 같은 방식으로 우리는 하한의 의미를 이해할 수 있습니다.
상한과 하한에 대해 너무 많이 말했는데, 그 용도는 무엇입니까? 어떻게 사용하나요? 간단히 말해서, 확장으로 한정된 유형 매개변수는 일반 객체에서 읽을 수 있고, super로 한정된 유형 매개변수는 일반 객체에 쓸 수 있습니다. 이런 말을 하면 어떤 아이들은 기절할 수도 있습니다. 이게 도대체 무슨 말입니까?
다르게 말하면 제네릭의 상한과 하한에 대한 공식이 요약되었습니다: PECS
PECS는 생산자 확장, 소비자 슈퍼
위의 의미는 매개변수화된 유형이 생산자를 나타내는 경우입니다. 소비자를 나타내는 경우 확장 T>를 사용하고, 소비자를 나타내는 경우 super T>를 사용합니다. 위의 설명과 함께 이해해 볼까요? 아직도 잘 이해가 되지 않는다면 Elephant는 차이점을 이해하기 위해 짧은 코드를 첨부합니다.
public void add(List 확장 T> list){
for(T t : list){
add(t);
}
}
public void add( T t){};
public void add(T t, List super T> list){
list.add(t);
}
일반 삭제
제네릭은 주로 즉, 컴파일 중에 유형 안전성이 확인됩니다. 요즘에는 일반적으로 Eclipse 또는 IntelliJ를 사용하여 코드를 작성합니다. 이러한 통합 개발 도구는 오류가 있는 경우 즉시 빨간색 오류 표시가 나타납니다. 따라서 유형 변환 오류가 발생하면 결과가 분명해집니다. 그러나 프로그램 실행 단계에서 JVM은 제네릭이 마법이라는 것을 인식하지 못합니다. 제네릭이 있는 모든 클래스, 인터페이스 및 메서드는 제네릭이 지워지고 원시 유형이 됩니다. 즉, Person가 됩니다. ;? T> 목록을 목록 목록으로 확장합니다.
다음은 이전 Person 클래스를 javap로 디컴파일한 결과입니다. T는 정규화되지 않은 유형이므로 모든 유형 변수가 지워졌습니다. 또한 add 메소드의 도 제거되었습니다.
public class com.bolo.Person은 java.lang.Object를 확장합니다.{
private java.lang.Object t;
public com.bolo.Person();
public java.lang.Object getT ();
public void setT(java.lang.Object);
public void add(java.util.List);
public void add(java.lang.Object);
public void add(java.lang. Object, java.util.List);
}
따라서 generic erasure 기능을 위해서는 다음 사항에 주의해야 합니다.
1. JVM에는 generic이 없고 일반만 있습니다. 클래스와 메소드.
2. 모든 유형 매개변수는 Object를 사용하여 정규화된 유형 또는 제한되지 않은 유형으로 대체됩니다.
3. 메소드 오버로딩을 주의해서 처리하십시오. 오버로딩을 잘못 사용하면 원하는 다형성을 얻을 수 없습니다.
4. 유형 안전성을 보장하기 위해 필요한 경우 강제 유형 변환을 사용하십시오.
제네릭의 한계
기본 유형은 유형 매개변수로 사용할 수 없습니다. Person가 잘못되었습니다. Person
유형 검사는 기본 유형만 사용할 수 있습니다. if(t 인스턴스of Person) if(t 인스턴스of Person)로 작성하면 즉시 컴파일 오류가 나타납니다.
유형 변수를 인스턴스화할 수 없습니다. 다음과 같이 쓰는 것은 잘못된 것입니다: T t = new T()
매개변수화된 유형의 배열을 인스턴스화할 수 없습니다. Person[] p = new Person[5] //ERROR
정적 인스턴스 변수와 정적 메서드는 정의할 수 없습니다. 다음과 같이 작성하고 싶다면: private static T a 그러면 죄송합니다. 컴파일러는 즉시 오류 메시지를 표시할 것입니다.
사실 제네릭에 대한 제한 사항에 대해 말할 필요가 없습니다. 이제 컴파일러는 매우 강력해지기 때문에 즉시 오류가 표시됩니다.
마지막으로 제네릭은 컬렉션에 가장 유용하며 컬렉션은 컨테이너이며 제네릭을 사용하면 재사용하기가 더 쉽습니다. 우리가 가장 자주 사용하는 컬렉션은 목록이고 다른 컨테이너는 배열입니다. 여기서 Elephant는 목록을 더 많이 사용하고 배열을 사용하지 않는 것이 좋습니다. 첫 번째는 List에 유형 안전성 검사가 있다는 것, 두 번째는 List가 배열의 모든 기능을 제공하고 더 풍부하다는 것, 세 번째는 List가 gc를 최적화한다는 것입니다. 배열을 사용하는 경우, 특히 객체 배열을 조작하는 경우 경험이 없고 배열의 객체 참조를 해제하지 않으면 메모리 누수가 발생하기 쉽습니다.



제네릭 사용 요약 및 리플렉션과 관련된 보다 일반적인 글은 PHP 중국어 홈페이지를 참고해주세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.