Java 범용 정의 및 사용 사례 상세 정보

8366 단어 Java범용
본고는 자바 범용 정의와 용법을 실례로 서술하였다.다음과 같이 여러분에게 참고할 수 있도록 공유합니다.

1. 범형의 유래


다음 코드를 참조하십시오.

import java.util.List;
import java.util.ArrayList;
public class TestGeneric {
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(1);
        list.add("1");
        list.add(new Object());
        System.out.println(list);
        //  
        Integer var1 = (Integer) list.get(0);
        String var2 = (String) list.get(1);
        Object var3 = list.get(2);
        System.out.println(var1 + " " + var2 + " " + var3);
    }
}

실행 결과:
[1, 1, java.lang.Object@1db9742]
1 1 java.lang.Object@1db9742
이 코드는 매우 간단합니다. 성형, 문자열, 대상을list 집합에 넣고 하나씩 꺼냅니다.이를 통해 알 수 있듯이 List 인터페이스는 정의할 때 요소의 종류를 알지 못하기 때문에 기본값은 Object입니다. 즉, 임의의 종류의 요소가list 집합에 들어가면 자동으로 포장됩니다.값을 얻는 과정은 더욱 복잡하다. 모든 값이 포장된 Object 대상이므로 모든 요소의 초기 유형을 알아야 상자를 뜯을 수 있다.일반적으로 집합을 사용할 때 집합된 원소는 흔히 공통된 특징을 가진다. 예를 들어 같은 종류에 속하는 것보다--- 만약에 처음에list 집합 원소의 유형을 한정했다면 상술한 규범에 맞지 않는 조작을 피할 수 있다.코드는 다음과 같습니다.

import java.util.List;
import java.util.ArrayList;
public class TestGeneric {
    @SuppressWarnings("unused")
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        // list.add(1);// 
        // list.add(new Object());// 
        list.add("1");
        //  
        String var1 = list.get(0);//  
    }
}

이렇게 되자 범형 집합이라는 말이 생겼다.실제로 List 인터페이스의 Api를 보면 List 인터페이스가 바로 범용 인터페이스로 유형 매개 변수 E를 받아들일 수 있으며 매개 변수를 전달하지 않으면 기본적으로 Object 형식입니다.

2. 범용 유형의 상속 관계


다음과 같은 기능이 있는 코드는 임의의 집합 요소를 인쇄합니다.

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric{
    // 
    public void print(Collection<Object> c){
     System.out.println(c);
    }
    public static void main(String[] args){
     List<String> list=new ArrayList<String>();
     new TestGeneric().print(list);
 }
}

출력:
TestGeneric.java:11:TestGeneric의 print(java.util.Collection)를 (java.util.List)에 적용할 수 없음
   new TestGeneric().print(list);
                    ^
1 오류
분명히 전달된 매개 변수 유형이 일치하지 않는다는 뜻이다.혹시 String이 Object에서 물려받은 거 아니에요?맞아요. String은 Object에서 계승된 것이지만 List<String>List<Object>는 전혀 다른 두 가지 유형입니다. 둘 사이에는 아무런 계승 관계가 없습니다.만약 정말 위의 기능을 실현하려면 어떻게 해야 합니까?

2.1 유형 와일드카드


import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric {
    //  
    public void print(Collection<?> c) {
        System.out.println(c);
    }
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        new TestGeneric().print(list);
    }
}

프로그램이 정상적으로 실행되고 있습니다. 여기?알 수 없는 유형을 나타냅니다. 이 알 수 없는 유형은 Object와 다릅니다. List모든 List<유형>의 상위 클래스를 나타냅니다.

2.2 범용 방법


어댑터만 범용 계승 문제를 해결할 수 있는 것이 아니라 위의 방법을 범용 방법으로 정의하면 같은 효과가 있다.

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric {
    //  
    public <T> void print(Collection<T> c) {
        System.out.println(c);
    }
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        new TestGeneric().print(list);
    }
}

범용 방법의 정의 형식은 다음과 같다.
수식자반환값 방법명(형삼)
그 중에서 는 수식자 뒤에 유형 정의를 하고 형삼에 필요한 T, E 유형이 어디에서 왔는지 가리킨다.범용 방법과 유형 어댑터가 범용 중의 계승을 실현할 수 있다면 어떤 차이가 있습니까?

2.3 범용 방법과 어댑터의 차이


다음 코드를 참조하십시오.

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric {
    //  
    public <E, T extends E> void print(Collection<T> c1, Collection<E> c2) {
        System.out.println(c1);
        System.out.println(c2);
    }
    public static void main(String[] args) {
        List<Father> list1 = new ArrayList<Father>();
        List<Father> list2 = new ArrayList<Father>();
        new TestGeneric().print(list1, list2);//  2 father 
        List<Child> list3 = new ArrayList<Child>();
        List<Father> list4 = new ArrayList<Father>();
        new TestGeneric().print(list3, list4);// T child,E father
        List<Father> list5 = new ArrayList<Father>();
        List<Child> list6 = new ArrayList<Child>();
        new TestGeneric().print(list5, list6);// T father,E child, 
    }
}
class Father {
}
class Child extends Father {
}
class Other {
}

상기 범용 방법은 T, E를 정의할 때 이미 관계를 가리켰다. T는 E의 자류이기 때문에 매개 변수를 전달할 때 T는 E의 자류이거나 E 자체이기 때문에 전달 관계가 조심하지 않아 E exends T로 변했을 때 세 번째 호출 방법이 틀렸다.상술한 코드를 바꾸면?어댑터의 경우 이렇게 강한 한정 관계를 가지지 않는다.
어쨌든, 범용 방법과?어댑터는 모두 미지의 유형의 계승을 실현할 수 있지만 범용 방법은 주로 여러 개의 미지의 유형 간의 의존 관계를 강조한다.단순히 통용되는 부류가 되는 기능으로만 사용한다면 둘 다 실현할 수 있다. 오히려?어댑터가 비교적 간결하고 명확하다.

2.4 범용 매개 변수의 상하한선에 대한 주의


다음 코드를 참조하십시오.

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric {
    //  
    public <T> T copy(Collection<T> des, Collection<? extends T> src) {
        T lastElement = null;
        for (T t : src) {
            lastElement = t;
            des.add(t);
        }
        return lastElement;
    }
    public static void main(String[] args) {
        List<Number> des = new ArrayList<Number>();
        List<Integer> src = new ArrayList<Integer>();
        src.add(new Integer(1));
        Integer lastElement = new TestGeneric().copy(des, src);//
        System.out.println(lastElement.getClass());
    }
}

출력:
TestGeneric.java:18: 호환되지 않는 형식
찾다:java.lang.Number
필요:java.lang.Integer
Integer lastElement= new TestGeneric().copy(des,src);//
                                              ^
1 오류
copy 방법을 다 사용한 후에 시스템은 T 유형이 Number인 것을 발견한 것보다,?유형은 Integer입니다.그래서 함수가 되돌아오는 T 형식은 Number이기 때문에 Integer가 호환되지 않습니다.위의 코드를 수정하려면 두 가지 방법이 있는데,
방법 1:
... 로 바꾸다

Number lastElement=new TestGeneric().copy(des,src);

코드를 분석하면,?T의 자류로 방법T=lastElement에서 이 표현은 다태적이다. 반환된 것은 T형이지만 다태의 표현은?유형, 즉 Interger 유형, 호출lastElement.getClass()도 자바로 되돌아오는 것을 발견할 수 있습니다.lang. Integer 유형, 여기서 컴파일 유형은 T 유형이고 실제 실행 유형은?유형이게 좋아요. 예를 들면 다태적 전환,

Father f=new Child();
Child c=f;// , 

f의 다태는 자류 차일드로 나타나지만 위의 문장은 문법 검사도 통과하지 못한다.이것이 바로 위의 Integer가 Number를 호환하지 못하는 이유입니다.
방법 2:
... 로 바꾸다

public <T> T copy(Collection<? super T> des,Collection<T> src)
이렇게 되면,?유형은 부류로 변하고 T유형은 자류로 변하기 때문에 방법에서 되돌아오는 T유형 대상, 즉lastElement는 다태성을 가지지 않는다.범형 중의 상하한은 매우 학문적이다. 원본을 볼 때마다 오랫동안 궁리하지만 넓은 인터페이스+범형 디자인에서 혼수상태에 빠진다. 이런 디자인은 정말 대상을 향한 특성을 돋보이게 하기 위해 앞으로 천천히 궁리하자.
이것도 다시 한 번 볼 수 있다?어댑터는 의존 관계를 가진 범용 방법을 처리하는 데 너무 유연해 보여서 잠재적인 위험을 초래할 수 있다.
자바 알고리즘과 관련된 내용에 관심이 있는 더 많은 독자들은 본 사이트의 주제를 볼 수 있습니다: Java 데이터 구조 및 알고리즘 튜토리얼, Java 운영 DOM 노드 기술 요약, 및 Java 파일과 디렉토리 작업 기술 요약
본고에서 기술한 것이 여러분의 자바 프로그램 설계에 도움이 되기를 바랍니다.

좋은 웹페이지 즐겨찾기