Java 범용 요약(二): 범용과 수조
지난 글은 범용 기본 사용법 및 유형 지우기의 문제를 소개했는데, 이제 범형과 수조의 관계를 살펴보자.수조는 자바 라이브러리의 용기 클래스에 비해 비교적 특수한 것으로 주로 세 가지 측면에 나타난다.
이 시리즈의 다른 두 문장:
범용 그룹을 만드는 방법
다음 클래스가 있는 경우
class Generic<T> {
}
범주형 그룹을 만들려면 다음과 같이 해야 한다. Generic<Integer> ga = new Generic<Integer>[]
행 코드가 틀리면 범주형 그룹을 직접 만들 수 없다는 것이다.그럼 범용수조를 사용하려면 어떻게 해야 하나요?한 가지 방안은 사용
ArrayList
이다. 예를 들어 다음과 같다.
public class ListOfGenerics<T> {
private List<T> array = new ArrayList<T>();
public void add(T item) { array.add(item); }
public T get(int index) { return array.get(index); }
}
어떻게 진정한 범주형 그룹을 만듭니까?우리는 직접 만들 수 없지만, 범용 그룹의 인용을 정의할 수 있습니다.예:
public class ArrayOfGenericReference {
static Generic<Integer>[] gia;
}
gia
는 범용 그룹을 가리키는 인용으로 이 코드는 컴파일할 수 있다.그러나 우리는 이 정확한 유형의 그룹을 만들 수 없다. 즉, 사용할 수 없다는 것이다. new Generic<Integer>[]
구체적인 예는 다음과 같다.
public class ArrayOfGeneric {
static final int SIZE = 100;
static Generic<Integer>[] gia;
@SuppressWarnings("unchecked")
public static void main(String[] args) {
// Compiles; produces ClassCastException:
//! gia = (Generic<Integer>[])new Object[SIZE];
// Runtime type is the raw (erased) type:
gia = (Generic<Integer>[])new Generic[SIZE];
System.out.println(gia.getClass().getSimpleName());
gia[0] = new Generic<Integer>();
//! gia[1] = new Object(); // Compile-time error
// Discovers type mismatch at compile time:
//! gia[2] = new Generic<Double>();
Generic<Integer> g = gia[0];
}
} /* :
Generic[]
*///:~
수조는 원소의 실제 유형을 추적할 수 있으며, 이 유형은 수조가 생성될 때 만들어진 것이다.위에서 설명한 코드 한 줄: gia = (Generic<Integer>[])new Object[SIZE]
, 그룹을 만들 때 Object 그룹입니다. 바꾸면 오류가 발생합니다.범용 그룹을 성공적으로 만드는 유일한 방법은 형식이 지워진 그룹을 만들고 변환하는 것입니다. 예를 들어 코드: gia = (Generic<Integer>[])new Generic[SIZE]
,gia의 클래스 대상 출력의 이름은Generic[]입니다.제 개인적인 이해는 유형이 지워졌기 때문에Generic
gia = (Generic<Integer>[])new Generic[SIZE]
중의 전환은 사실은Generic[]로 바뀌었습니다. 보기에는 회전하지 않은 것 같지만 컴파일러가 매개 변수에 대한 검사와 자동 전환을 많이 하면 수조에 삽입new Object()
과new Generic<Double>()
모두 오류를 보고하고gia[0]를 추출Generic<Integer>
도 우리가 수동으로 전환할 필요가 없습니다.T[]array 사용
위의 예에서 원소의 유형은 범형류이다.다음은 요소 자체 유형이 범용 매개변수의 예입니다.
public class GenericArray<T> {
private T[] array;
@SuppressWarnings("unchecked")
public GenericArray(int sz) {
array = (T[])new Object[sz]; //
}
public void put(int index, T item) {
array[index] = item;
}
public T get(int index) { return array[index]; }
// Method that exposes the underlying representation:
public T[] rep() { return array; } //
public static void main(String[] args) {
GenericArray<Integer> gai =
new GenericArray<Integer>(10);
// This causes a ClassCastException:
//! Integer[] ia = gai.rep();
// This is OK:
Object[] oa = gai.rep();
}
}
위의 코드에서 범용 그룹을 만드는 것은 Object 그룹을 만들고 T[]로 바꾸는 것입니다.그러나 배열의 실제 유형은 Object[]입니다.Rep () 메서드를 호출할 때 ClassCastException 이상이 발생했습니다. Object[]에서 Integer[]로 전환할 수 없기 때문입니다.그러면 범용 그룹을 만드는 코드
array = (T[])new Object[sz]
는 왜 오류를 보고하지 않습니까?제 이해는 앞에서 소개한 것과 유사합니다. 유형이 지워져서 Object[]
로 바뀌는 것과 같습니다. 보기에는 회전하지 않은 것 같지만 컴파일러의 매개 변수 검사와 자동 전환이 많습니다.범용 매개 변수를 <T extends Integer>
로 바꾸면 유형이 첫 번째 경계로 지워지기 때문에 array = (T[])new Object[sz]
에서 Integer[]
로 바뀌는 것과 같아서 오류가 발생할 수 있습니다.다음은 실험 코드입니다.
public class GenericArray<T extends Integer> {
private T[] array;
@SuppressWarnings("unchecked")
public GenericArray(int sz) {
array = (T[])new Object[sz]; //
}
public void put(int index, T item) {
array[index] = item;
}
public T get(int index) { return array[index]; }
// Method that exposes the underlying representation:
public T[] rep() { return array; } //
public static void main(String[] args) {
GenericArray<Integer> gai =
new GenericArray<Integer>(10);
// This causes a ClassCastException:
//! Integer[] ia = gai.rep();
// This is OK:
Object[] oa = gai.rep();
}
}
원본 버전에 비해 위의 코드는 첫 줄만 수정하고 <T>
를 <T extends Integer>
로 바꾸면 Rep () 를 호출하지 않고 범용 그룹을 만들 때 오류를 보고합니다.다음은 실행 결과입니다.
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
at GenericArray.<init>(GenericArray.java:15)
Object[] array 사용하기지우기 때문에, 실행 기간의 그룹 형식은 Object[]일 뿐입니다. 만약 우리가 즉시 그것을 T[]로 바꾸면, 컴파일러는 그룹의 실제 형식을 잃고, 컴파일러는 잠재적인 오류를 발견할 수 없습니다.따라서 더 좋은 방법은 내부에서 Object[] 수조를 사용하고 원소를 꺼낼 때 바꾸는 것이다.다음 예제를 참조하십시오.
public class GenericArray2<T> {
private Object[] array;
public GenericArray2(int sz) {
array = new Object[sz];
}
public void put(int index, T item) {
array[index] = item;
}
@SuppressWarnings("unchecked")
public T get(int index) { return (T)array[index]; }
@SuppressWarnings("unchecked")
public T[] rep() {
return (T[])array; // Warning: unchecked cast
}
public static void main(String[] args) {
GenericArray2<Integer> gai =
new GenericArray2<Integer>(10);
for(int i = 0; i < 10; i ++)
gai.put(i, i);
for(int i = 0; i < 10; i ++)
System.out.print(gai.get(i) + " ");
System.out.println();
try {
Integer[] ia = gai.rep();
} catch(Exception e) { System.out.println(e); }
}
} /* Output: (Sample)
0 1 2 3 4 5 6 7 8 9
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
*///:~
현재 내부 그룹의 표현은 T[]가 아니라 Object[]입니다. get () 가 호출될 때 그룹의 요소가 T로 바뀌는 것이 바로 요소의 실제 유형입니다.그러나rep()를 호출하면 오류가 발생합니다. 그룹의 실제 형식은 여전히 Object[]이기 때문에 다른 형식으로 변환할 수 없습니다.T[] 대신 Object[]를 사용하는 장점은 그룹 운행 기간의 실제 유형을 잊지 않고 실수로 오류를 도입하는 것이다.유형 ID 사용
사실 Class 객체를 유형 표식으로 사용하는 것이 더 좋은 디자인입니다.
public class GenericArrayWithTypeToken<T> {
private T[] array;
@SuppressWarnings("unchecked")
public GenericArrayWithTypeToken(Class<T> type, int sz) {
array = (T[])Array.newInstance(type, sz);
}
public void put(int index, T item) {
array[index] = item;
}
public T get(int index) { return array[index]; }
// Expose the underlying representation:
public T[] rep() { return array; }
public static void main(String[] args) {
GenericArrayWithTypeToken<Integer> gai =
new GenericArrayWithTypeToken<Integer>(
Integer.class, 10);
// This now works:
Integer[] ia = gai.rep();
}
}
구조기에서 Class<T>
대상을 전송하고 Array.newInstance(type, sz)
을 통해 그룹을 만듭니다. 이 방법은 매개 변수의 클래스 대상을 그룹 요소의 구성 요소 형식으로 사용합니다.이렇게 생성된 배열의 요소 유형은 Object가 아니라 T입니다.이 방법은 Object 대상을 되돌려줍니다. 그것을 그룹으로 전환해야 합니다.그러나 다른 조작은 Rep () 방법을 포함할 필요가 없다. 왜냐하면 수조의 실제 유형은 T[]와 일치하기 때문이다.이것은 비교적 추천하는 범형수 그룹을 만드는 방법이다.총결산
수조와 범형의 관계는 여전히 좀 복잡하다. 자바에서는 범주를 직접 만드는 것을 허락하지 않는다.본고는 그 중의 원인을 분석하고 범형수조를 만드는 방식을 총결하였다.그 중 일부는 개인의 이해가 있기 때문에 잘못되면 여러분이 바로잡아 주시기 바랍니다.다음 편은 총결산할 것이다와일드카드 사용.
이상은 본문의 전체 내용입니다. 본고의 내용이 여러분의 학습이나 업무에 일정한 도움을 줄 수 있는 동시에 저희를 많이 지지해 주시기 바랍니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
38. Java의 Leetcode 솔루션텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.