>  기사  >  Java  >  Java 제네릭에 대한 자세한 설명

Java 제네릭에 대한 자세한 설명

高洛峰
高洛峰원래의
2016-12-19 14:58:461217검색
  1. 개요
    제네릭이 도입되기 전에는 Java 유형을 기본 유형과 복합 유형으로 구분했습니다. 제네릭을 도입한 후 복잡한 유형
    을 더 많은 유형으로 세분화할 수 있습니다.
    예를 들어 원래 유형인 List는 이제 List, List 및 기타 유형으로 세분화됩니다.
    List와 List은 서로 다른 두 가지 유형입니다.
    String이 Object를 상속하더라도 이들 사이에는 상속 관계가 없습니다. 다음 코드는 불법입니다.
    List ls = new ArrayList();
    List lo = ls;
    이 디자인의 이유는 lo의 설명에 따르면, 컴파일러를 사용하면 임의의 개체(예: Integer)를 lo에 추가할 수 있지만 이 개체는
    List이므로 데이터 유형의 무결성이 파괴됩니다.
    제네릭을 도입하기 전에는 클래스의 메서드가 여러 데이터 유형을 지원하는 경우 메서드를 오버로드해야 합니다. 제네릭을 도입한 후에는 이 문제를 해결할 수 있습니다
    (다형성). 여러 매개변수와 반환 값 사이.
    예를 들어
    public void write(Integer i, Integer[] ia);
    public void write(Double d, Double[] da);
    의 일반 버전은
    public입니다. < T> void write(T t, T[] ta);

    2. 정의 및 사용
    유형 매개변수의 이름 지정 스타일은 다음과 같습니다.
    다음과 같이 간결한 이름을 사용하는 것이 좋습니다. 형식 유형 매개변수의 이름(가능한 경우 단일 문자) 다른 일반
    형식 매개변수와 구별하기 쉽도록 소문자를 사용하지 않는 것이 가장 좋습니다.
    구분할 특정 유형이 더 이상 없을 때마다 유형에 T를 사용합니다. 이는 일반적인 방법에서 흔히 볼 수 있습니다. 유형 매개변수가 여러 개인 경우
    S와 같이 알파벳에서 T에 가까운 문자를 사용할 수 있습니다.
    제네릭 클래스 내에 제네릭 함수가 나타나는 경우 혼동을 피하기 위해 메서드의 유형 매개변수와 클래스의 유형 매개변수에 동일한 이름을 사용하지 않는 것이 가장 좋습니다
    . 내부 클래스도 마찬가지입니다.

    2.1 유형 매개변수를 사용하여 클래스 정의
    유형 매개변수를 사용하여 클래스를 정의할 때 클래스 이름 바로 뒤의 <>에 하나 이상의 유형 매개변수 이름을 지정하고 유형 매개변수의
    값 범위, 기호로 여러 유형 매개변수를 구분합니다.
    유형 매개변수를 정의한 후에는 일반 유형을 사용하는 것처럼
    정의 위치 이후 클래스의 거의 모든 위치에서 유형 매개변수를 사용할 수 있습니다(정적 블록, 정적 속성, 정적 메소드 제외).
    상위 클래스에서 정의한 유형 매개변수는 하위 클래스에서 상속될 수 없습니다.
    public class TestClassDefine {
    ....
    }

    2.2 유형 매개변수를 사용하여 메소드 정의
    유형 매개변수를 사용하여 메소드를 정의하는 경우 <> 가시 범위 수정(예: 공개) 직후에 하나 이상의 유형 매개변수의 이름을 지정합니다.
    동시에 유형 매개변수의 값 범위를 로 구분하여 제한할 수도 있습니다. 징후.
    유형 매개변수를 정의한 후에는 일반 유형을 사용할 때와 마찬가지로 메소드 정의 위치 이후 어디에서나 유형 매개변수를 사용할 수 있습니다.
    예:
    public T testGenericMethodDefine(T t, S s){
    ...
    }
    참고: 유형 매개변수를 사용하여 메소드를 정의하려면 , ride 주요 목적은 여러 매개 변수와 반환 값 간의 관계를 표현하는 것입니다. 예를 들어, 이 예의 T와 S 사이의
    상속 관계에서 반환 값의 유형은 첫 번째 유형 매개 변수의 값과 동일합니다.
    단지 다형성을 구현하고 싶다면 먼저 와일드카드를 사용하세요. 와일드카드 내용은 다음 섹션을 참조하세요.
    public void testGenericMethodDefine2(List s){
    ...
    }

    public void testGenericMethodDefine2(List s){로 변경되어야 합니다.
    ...
    }

    3. 타입 매개변수 할당
    클래스나 메소드의 유형 매개변수에 값을 할당할 때는 모든 유형 매개변수를 할당해야 합니다. 그렇지 않으면 컴파일 오류가 발생합니다.

    3.1 유형 매개변수를 사용하여 클래스에 유형 매개변수 할당
    유형 매개변수를 사용하여 클래스에 유형 매개변수를 할당하는 방법에는 두 가지가 있습니다.
    첫째, 클래스 변수를 선언하거나 인스턴스화할 때입니다. 예를 들어 두 번째 상속 클래스 또는 인터페이스를 구현하는 경우
    List list;
    list = new ArrayList;;
    입니다. 예를 들어
    public class MyList Implements List , 컴파일 컴파일러는 자동으로 유형 매개변수에 값을 할당합니다. 할당이 성공하지 못하면 컴파일 오류가 보고됩니다. 예를 들어
    공개 T testGenericMethodDefine3(T t, List list){
    ...
    }
    공개 T testGenericMethodDefine4(List list1, List list2 ){
    ...
    }

    숫자 n = null;
    정수 i = null;
    객체 o = null;
    testGenericMethodDefine(n, i);/ /이때 T는 Number, S는 정수
    testGenericMethodDefine(o, i);//T는 Object, S는 정수

    List list1 = null;
    testGenericMethodDefine3(i , list1)//이때 T는 숫자

    List list2 = null;
    testGenericMethodDefine4(list1, list2)//컴파일 오류

    3.3 와일드카드
    위의 두 가지 항목에서는 특정 값을 유형 매개변수에 할당합니다. 또한 정의되지 않은 값을 유형 매개변수에 할당할 수도 있습니다. 예를 들어
    List>UnknownList;
    List
    참고: Java 컬렉션 프레임워크에서 매개변수 값은 다음과 같습니다. 유형을 알 수 없는 컨테이너 클래스는 해당 요소를 읽을 수만 있고 요소를 추가할 수는 없습니다.
    유형을 알 수 없기 때문에 컴파일러는 추가된 요소의 유형이 컨테이너 유형과 호환되는지 확인할 수 없습니다. 유일한 예외는 NULL

    List listString;
    ListknownList2 = listString;
    knownList =knownList2;
    listString=knownList;//Compilation error

    4. 배열 지정 유형
    일반 매개변수 값이 있는 클래스를 사용하여 배열을 선언할 수 있지만 배열을 생성할 수는 없습니다.
    List new ArrayList< 정수>[10];//컴파일 타임 오류

    5. 구현 원칙

    5.1. Java 일반 컴파일 타임 기술은 런타임 시 일반 정보를 포함하지 않습니다. 유형 매개변수.
    제네릭은 Java 컴파일러에 의한 삭제라는 프런트엔드 프로세스를 통해 구현됩니다. (기본적으로) 일반 버전을 일반 버전이 아닌 버전으로 변환하는 소스-소스 변환으로 생각할 수 있습니다.
    기본적으로 삭제는 모든 일반 유형 정보를 제거합니다. 꺾쇠 괄호 사이의 모든 유형 정보는 버려지므로, 예를 들어
    List 유형 변수에 대한 모든 참조는 유형 변수(일반적으로 Object)의 상한으로 대체됩니다. 또한
    결과 코드 유형이 올바르지 않을 때마다 적절한 유형으로의 변환이 삽입됩니다.
                                                                                                                                                                                이는 시간이나 공간 오버헤드를 추가하지 않는다는 것을 의미하며 이는 좋은 일입니다. 불행하게도 이는
    유형 변환에 의존할 수 없다는 의미이기도 합니다.

    5.2. 일반 클래스는 모든 호출에 의해 공유됩니다.
    다음 코드의 결과는 무엇입니까?
    List l1 = new ArrayList();
    List l2 = new ArrayList();
    System.out.println(l1.getClass() == l2.getClass());
    거짓이라고 말할 수도 있지만 틀렸습니다. 그것은 사실로 인쇄됩니다. 일반 클래스의 모든 인스턴스는 실제 유형 매개변수에 관계없이 런타임에 동일한 런타임 클래스를 갖기 때문입니다.
    사실 제네릭을 제네릭이라고 부르는 이유는 동일한 클래스가 다양한
    유형으로 사용될 수 있기 때문입니다. 결과적으로 클래스의 정적 변수와 메서드도 모든 인스턴스에서 공유됩니다. 이것이 정적 메서드나 정적 초기화 코드
    에서 또는 정적 변수를 선언하고 초기화할 때 유형 매개변수(특정 인스턴스에 속하는 유형 매개변수)를 사용하는 것이 불법인 이유입니다.

    5.3. 캐스팅 및 인스턴스
    일반 클래스가 모든 인스턴스에서 공유된다는 또 다른 의미는 인스턴스가 특정 유형의 일반 클래스인지 확인하는 것이 의미가 없다는 것입니다.
    Collection cs = new ArrayList();
    if (cs instanceof Collection) { ...} // Illegal
    마찬가지로 다음 유형 변환
    Collection cstr = (Collection) cs;
    런타임 환경이 이러한 확인을 수행하지 않으므로 확인되지 않은 경고를 받습니다.

    6. 클래스의 일반 처리
    Java 5 이후에는 클래스가 일반화됩니다.
    JDK1.5의 변경 사항 중 하나는 java.lang.Class 클래스가 일반 클래스라는 것입니다. 이는 컨테이너 클래스를 넘어 제네릭을 확장하는 흥미로운 예입니다.
    이제 클래스에는 유형 매개변수 T가 있습니다. T가 무엇을 의미하는지 궁금하실 수도 있습니다. Class 객체가 나타내는 유형을 나타냅니다. 예를 들어,
    String.class 유형은 Class을 나타내고 Serialized.class는 Class를 나타냅니다.
    이는 반영된 코드의 유형 안전성을 향상시키는 데 사용될 수 있습니다.
    특히 이제 Class의 newInstance() 메서드가 T를 반환하므로 리플렉션을 사용하여 객체를 생성할 때 더 정확한 유형을 얻을 수 있습니다.
    예를 들어, SQL 문이 주어지면 데이터베이스 쿼리를 수행하고 쿼리 조건을 충족하는 데이터베이스의 개체 컬렉션을 반환하는 도구 메서드를 작성한다고 가정합니다
    .
    한 가지 방법은 다음 코드와 같이 팩토리 객체를 명시적으로 전달하는 것입니다.
    interface Factory {
    public T[] make();
    }
    public Collection select(Factory Factory, String 문) {
    Collection result = new ArrayList();
    /* jdbc를 사용하여 SQL 쿼리 실행 */
    for ( int i=0; i<10; i++ ) { /* jdbc 결과 반복 */
              T 항목 = Factory.make();
                                                                                                    /
             result.add( 항목); {
                                                                                                               >
    }
    다음을 호출하세요:
    select(getMyEmpInfoFactory(), "selection string" );
    이 솔루션의 단점은 두 가지 중 하나가 필요하다는 것입니다.
    호출 사이트에 장황한 익명 팩토리 클래스가 있거나, 사용할 각 유형에 대한 팩토리 클래스를 선언하고 해당 객체를 호출에 전달하는 것입니다. 사이트
    부자연스럽네요.
    클래스 유형 매개변수 값을 사용하는 것은 매우 자연스럽고 반영하여 사용할 수 있습니다. 제네릭이 없는 코드는 다음과 같습니다.
    Collection emps = sqlUtility.select(EmpInfo.class, ”select * from emps”) ...
    public static Collection select(Class c, String sqlStatement) {
    Collection result = new ArrayList();
    /* jdbc를 사용하여 SQL 쿼리 실행 */
    for ( /* jdbc 결과 반복 */ ) {
    개체 항목 = c.newInstance();
                                      ~ 결과 .add(item); 우리가 원하는 정확한 컬렉션 유형입니다. 이제 Class가 일반화되었으므로 다음과 같이 작성할 수 있습니다.
    Collection emps=sqlUtility.select(EmpInfo.class, ”select * from emps”) ...
    public static ; select(Classc, String sqlStatement) {
    Collection result = new ArrayList();
    /* jdbc를 사용하여 SQL 쿼리 실행 */
    for ( /* 반복 jdbc 결과에 대해 */ ) {
    T item = c.newInstance();
    /* 리플렉션을 사용하고 SQL 결과에서 항목의 모든 필드를 설정 */
    result.add(item);
    }
    return result;
    }
    유형이 안전한 방식으로 원하는 컬렉션을 가져옵니다.
    이 기술은 주석을 처리하는 새로운 API에서 널리 사용되는 관용구가 된 매우 유용한 트릭입니다.

    7. 기존 코드와 새 코드의 호환성

    7.1. 코드 호환성을 보장하기 위해 다음 코드 컴파일러(javac)가 허용하며 유형 안전성은 스스로 보장됩니다.
    목록 l = new ArrayList();
    List l = new ArrayList();

    7.2. 클래스 라이브러리를 일반 버전으로 업그레이드하는 경우 공변 반환 값을 주의해서 사용하세요.
    예를 들어 코드를 변경하세요
    public class Foo {
    public Foo create(){
    } return new Foo();
    }
    }

    public 클래스 Bar는 Foo를 확장합니다 {
    공개 Foo 생성(){
                                                                                                                                                                     사용   공변 반환 값 사용         사용             ‐ } ‐ } ‐ }                                                                pblic bar create () {
    Return New Bar ()
    }
    }
    도서관의 고객을 조심하십시오.




    Java Generic과 관련된 더 많은 글은 PHP 중국어 홈페이지를 주목해주세요!


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