Java에서 일반 배열 유형을 만들 수없는 이유는 무엇입니까?


273

Java가 우리를 허용하지 않는 이유는 무엇입니까?

private T[] elements = new T[initialCapacity];

.NET에서 런타임에 다른 크기를 가질 수있는 값 유형이 있기 때문에 .NET이 그렇게 할 수 없다는 것을 이해할 수 있었지만 Java에서는 모든 종류의 T가 객체 참조이므로 동일한 크기 ( 틀 렸으면 말해줘).

이유가 무엇입니까?


29
무슨 소리 야? .NET에서이 작업을 수행 할 수 있습니다. -나는 왜 Java로 그것을 할 수 없는지 알아 내려고 노력 중이다.
BrainSlugs83

@ BrainSlugs83-코드 예제 또는 튜토리얼에 대한 링크를 추가하십시오.
MasterJoe2


1
@ MasterJoe2 OP의 질문에서 위 코드는 내가 말하는 것입니다. C #에서는 잘 작동하지만 Java에서는 작동하지 않습니다. -문제는 둘 다 작동하지 않는다는 것을 나타냅니다. -더 논의 할 가치가 있는지 확실하지 않습니다.
BrainSlugs83

답변:


204

제네릭과 달리 Java의 배열에는 런타임에 구성 요소 유형에 대한 정보가 포함되어 있기 때문입니다. 따라서 배열을 만들 때 구성 요소 유형을 알아야합니다. T런타임에 무엇인지 모르므로 배열을 만들 수 없습니다.


29
그러나 소거는 어떻습니까? 왜 적용되지 않습니까?
Qix-MONICA가 MISTREATED했습니다.

14
그러면 어떻게 ArrayList <SomeType>합니까?
Thumbz

10
@Thumbz : 그러세요 new ArrayList<SomeType>()? 일반 유형은 런타임시 유형 매개 변수를 포함하지 않습니다. type 매개 변수는 작성에 사용되지 않습니다. 에 의해 생성 된 코드에는 차이가 없다 new ArrayList<SomeType>()거나 new ArrayList<String>()또는 new ArrayList()전혀은.
newacct

8
나는 ArrayList<T>그것의 작동 방식 에 대해 더 묻고 있었다 private T[] myArray. 코드 어딘가에 제네릭 형식 T의 배열이 있어야합니다. 어떻게?
Thumbz

21
@Thumbz : 런타임 유형의 배열이 없습니다 T[]. 런타임 유형의 배열이 Object[]있으며 1) 소스 코드에 변수가 들어 있습니다 Object[](이것이 최신 Oracle Java 소스에있는 방법입니다). 또는 2) 소스 코드에 유형의 변수가 포함되어 있습니다.이 변수 T[]는 거짓말이지만 T클래스 범위 내에서 지워져서 문제가 발생하지 않습니다 .
newacct

137

인용문:

제네릭 형식의 배열은 소리가 나지 않으므로 사용할 수 없습니다. 문제는 정적으로 건전하지 않지만 동적으로 확인되는 Java 배열과 정적으로 건전하고 동적으로 확인되지 않은 제네릭을 사용하여 상호 작용하기 때문입니다. 허점을 활용하는 방법은 다음과 같습니다.

class Box<T> {
    final T x;
    Box(T x) {
        this.x = x;
    }
}

class Loophole {
    public static void main(String[] args) {
        Box<String>[] bsa = new Box<String>[3];
        Object[] oa = bsa;
        oa[0] = new Box<Integer>(3); // error not caught by array store check
        String s = bsa[0].x; // BOOM!
    }
}

Tiger에서는 거부 된 정적 안전 배열 (일명 Variance) 버트를 사용하여이 문제를 해결하도록 제안했습니다.

- 사후

(나는 그것이 Neal Gafter 라고 생각 하지만 확실하지 않습니다)

컨텍스트에서 참조하십시오 : http://forums.sun.com/thread.jspa?threadID=457033&forumID=316


3
대답이 내 것이 아니기 때문에 CW로 만들었습니다.
Bart Kiers

10
타입이 안전하지 않은 이유를 설명합니다. 그러나 형식 안전 문제는 컴파일러에서 경고 할 수 있습니다. 사실 당신이 할 수없는 이유와 거의 같은 이유로 할 수조차 없습니다 new T(). Java의 각 배열은 설계 상으로 구성 요소 유형 (예 :)을 저장 T.class합니다. 따라서 이러한 배열을 만들려면 런타임에 T 클래스가 필요합니다.
newacct

2
귀하 new Box<?>[n]의 예제에서는 도움이되지 않지만 때때로 충분할 수도 있습니다.
Bartosz Klimek

1
@BartKiers 나는 그것을 얻지 못한다 ... 이것은 여전히 ​​컴파일하지 않는다 (java-8) : Box<String>[] bsa = new Box<String>[3];java-8에서 아무것도 바뀌지 않았다.
Eugene

1
@Eugene, 특정 제네릭 형식의 배열은 샘플에서 보여 지듯이 형식 안전성의 손실로 이어질 수 있기 때문에 단순히 허용되지 않습니다. 모든 버전의 Java에서는 허용되지 않습니다. 대답은 "제네릭 형식의 배열은 소리가 나지 않기 때문에 허용되지 않습니다."로 시작합니다.
garnet

47

적절한 솔루션을 제공하지 않으면 더 나쁜 IMHO로 끝납니다.

일반적인 해결 방법은 다음과 같습니다.

T[] ts = new T[n];

(T가 다른 클래스가 아닌 Object를 확장한다고 가정)

T[] ts = (T[]) new Object[n];

나는 첫 번째 예를 선호하지만 더 많은 학업 유형이 두 번째 예를 선호하거나 생각하지 않는 것을 선호합니다.

Object []를 사용할 수없는 이유의 대부분의 예는 List 또는 Collection (지원되는)에 동일하게 적용되므로 매우 나쁜 인수로 간주합니다.

참고 : 이것이 Collections 라이브러리 자체가 경고없이 컴파일되지 않는 이유 중 하나입니다. 이 사용 사례를 경고없이 지원할 수없는 경우 제네릭 모델 IMHO에서 근본적으로 문제가 발생합니다.


6
두 번째 것을 조심해야합니다. 예를 들어 a String[](또는 공개적으로 액세스 가능한 유형의 필드에 저장하고 검색하는 필드) 에 이러한 방식으로 작성된 배열을 리턴하면 T[]ClassCastException이 발생합니다.
newacct

4
원하는 예는 ClassCastException이 던질 수 Java 및 두 번째 예에서 허용되지 않기 때문에 나는이 대답을 부결
호세 로베르토 아라 우호 주니어

5
@ JoséRobertoAraújoJúnior 첫 번째 예제를 두 번째 예제로 바꿔야한다는 것은 분명합니다. 왜 두 번째 예제가 ClassCastException을 던질 수 있는지 설명하는 것이 더 도움이 될 것입니다.
Peter Lawrey

3
@PeterLawrey 나는 왜 자기 대답 질문 보여주는 생성 T[] ts = (T[]) new Object[n];: 나쁜 생각 stackoverflow.com/questions/21577493/...
호세 로베르토 아라 우호 주니어

1
@MarkoTopolnik 나는 내가 말했던 것과 똑같은 것을 설명하기 위해 모든 당신의 의견에 답하기 위해 메달을 받아야합니다. 원래의 이유와 다른 유일한 것은 그가 T[] ts = new T[n];유효한 사례 라고 말했지만 . 나는 그 답변이 다른 개발자들에게 문제와 혼란을 야기 할 수 있고 주제를 벗어 났기 때문에 투표를 계속할 것입니다. 또한 이것에 대한 언급을 중단합니다.
José Roberto Araújo Júnior

38

배열은 공변량입니다

배열은 공변량이라고하며 기본적으로 Java의 하위 유형 지정 규칙에서 유형의 배열은 유형의 T[]요소 T또는의 하위 유형을 포함 할 수 있습니다 T. 예를 들어

Number[] numbers = new Number[3];
numbers[0] = newInteger(10);
numbers[1] = newDouble(3.14);
numbers[2] = newByte(0);

그러나 Java의 하위 유형 지정 규칙은 또한 S[]의 하위 유형 인 경우 배열이 배열 의 하위 유형이라고 T[]명시 하므로 다음과 같은 것도 유효합니다.ST

Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;

Java의 하위 유형 지정 규칙에 따라 배열 Integer[]은 배열 의 하위 유형이므로Number[] 정수는 숫자의 하위 유형이므로 의 하위 유형입니다.

그러나이 하위 유형 규칙은 흥미로운 질문으로 이어질 수 있습니다. 우리가 이것을 시도하면 어떻게 될까요?

myNumber[0] = 3.14; //attempt of heap pollution

이 마지막 줄은 잘 컴파일되지만이 코드를 실행하면 ArrayStoreException 하면 정수 배열에 double을 넣으려고하기 때문에 있습니다. 여기서 Number 참조를 통해 배열에 액세스한다는 사실은 중요하지 않습니다. 중요한 것은 배열이 정수 배열이라는 것입니다.

이는 컴파일러를 속일 수는 있지만 런타임 유형 시스템을 속일 수는 없다는 것을 의미합니다. 배열은 우리가 reifiable 타입이라고 부르기 때문입니다. 이는 런타임시 Java가이 배열이 실제로 유형의 참조를 통해 액세스되는 정수 배열로 인스턴스화되었음을 알고 있음을 의미합니다.Number[] .

보시다시피, 하나는 객체의 실제 유형이고 다른 하나는 객체에 액세스하는 데 사용하는 참조의 유형입니다.

자바 제네릭의 문제점

이제 Java에서 제네릭 형식의 문제점은 코드 컴파일이 완료된 후 형식 매개 변수의 형식 정보가 컴파일러에 의해 삭제된다는 것입니다. 따라서이 유형 정보는 런타임에 사용할 수 없습니다. 이 과정을 유형 삭제 라고 합니다 . Java에서 이와 같은 제네릭을 구현하는 데는 합당한 이유가 있지만, 이는 오랜 이야기이며 기존 코드와 바이너리 호환성과 관련이 있습니다.

여기서 중요한 점은 런타임에 유형 정보가 없기 때문에 힙 오염을 저 지르지 않도록 보장 할 방법이 없다는 것입니다.

다음과 같은 안전하지 않은 코드를 살펴 보겠습니다.

List<Integer> myInts = newArrayList<Integer>();
myInts.add(1);
myInts.add(2);
List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap polution

Java 컴파일러가이를 수행하지 못하게하는 경우 런타임 유형 시스템은 런타임시이 목록이 정수 목록으로 만 가정 된 방법이 없기 때문에 중지 할 수 없습니다. Java 런타임은 정수만 포함해야 할 때이 목록에 원하는 것을 넣을 수 있습니다. 생성 될 때 정수 목록으로 선언 되었기 때문입니다. 그렇기 때문에 컴파일러는 라인 번호 4를 안전하지 않기 때문에 거부합니다.

따라서 Java 디자이너는 컴파일러를 속일 수 없도록했습니다. 우리가 컴파일러를 속일 수 없다면 (배열로 할 수있는 것처럼) 런타임 타입 시스템을 속일 수 없습니다.

따라서 런타임에 일반 유형의 실제 특성을 판별 할 수 없으므로 일반 유형은 수정할 수 없다고 말합니다.

이 답변의 일부를 건너 뛰었습니다. https://dzone.com/articles/covariance-and-contravariance


32

이것이 불가능한 이유는 Java가 컴파일러 레벨에서 순수하게 Generics를 구현하고 각 클래스마다 하나의 클래스 파일 만 생성되기 때문입니다. 이것을 유형 소 거라고합니다. 합니다.

런타임시 컴파일 된 클래스는 모든 사용을 동일한 바이트 코드로 처리해야합니다. 따라서 new T[capacity]어떤 유형을 인스턴스화해야하는지 전혀 모를 것입니다.


17

대답은 이미 제공되었지만 이미 인스턴스가 T 인 경우 다음을 수행 할 수 있습니다.

T t; //Assuming you already have this object instantiated or given by parameter.
int length;
T[] ts = (T[]) Array.newInstance(t.getClass(), length);

희망, 나는 도울 수 있었다, Ferdi265


1
이것은 좋은 해결책입니다. 그러나 이것은 확인되지 않은 경고를받습니다 (Object에서 T []로 캐스트). "느린"그러나 "경고없는"솔루션은 다음과 같습니다 T[] ts = t.clone(); for (int i=0; i<ts.length; i++) ts[i] = null;..
midnite

1
또한, 우리가 유지 T[] t한 것이이면 그렇습니다 (T[]) Array.newInstance(t.getClass().getComponentType(), length);. 나는 알아 내기 위해 몇 시간을 보냈다 getComponentType(). 이것이 다른 사람들을 돕기를 바랍니다.
midnite

1
@midnite t.clone()는 반환하지 않습니다 T[]. t이 답변에서 배열이 아니기 때문 입니다.
xmen

6

주된 이유는 Java의 배열이 공변량이기 때문입니다.

여기에 좋은 개요가 있습니다 .


고정 배열에서도 "새 T [5]"를 어떻게 지원할 수 있는지 모르겠습니다.
Dimitris Andreou

2
@DimitrisAndreou 글쎄, 모든 것은 자바 디자인에서 오류의 코미디입니다. 모두 배열 공분산으로 시작했습니다. 당신이 배열 공분산을 일단 그런 다음, 당신은 캐스트 할 수 있습니다 String[]Object와 저장 Integer거기에. 따라서 ArrayStoreException컴파일 타임에 문제를 잡을 수 없으므로 배열 저장소 ( )에 대한 런타임 유형 검사를 추가해야했습니다 . (그렇지 않으면, Integer실제로는에 갇힐 수 있으며 String[], 검색하려고 할 때 오류가 발생하여 끔찍할 수 있습니다.) ...
Radon Rosborough

2
@DimitrisAndreou… 그런 다음 훨씬 더 컴파일 타임 검사 대신 런타임 검사를 수행하면 유형 삭제 (불행한 설계 결함-이전 버전과의 호환성을 위해서만 포함됨)가 발생합니다. 유형 삭제는 일반 유형에 대한 런타임 유형 검사를 수행 할 수 없음을 의미합니다 . 따라서 배열 스토리지 유형 문제를 피하려면 일반 배열을 사용할 수 없습니다. 배열을 처음부터 변경하지 않으면 삭제를 무시하지 않고 컴파일 타임 유형 검사를 수행 할 수 있습니다.
Radon Rosborough

… 댓글 작성을위한 5 분의 편집 기간을 발견했습니다. 내 첫 의견에 Object있었어야 Object[]했어요
Radon Rosborough

3

나는 Gafter에 의해 간접적으로 주어진 대답을 좋아한다 . 그러나 나는 그것이 틀렸다고 제안한다. 나는 Gafter의 코드를 약간 변경했습니다. 컴파일하고 잠시 동안 실행 한 다음 Gafter가 예상 한 곳에서 폭탄을 터트립니다.

class Box<T> {

    final T x;

    Box(T x) {
        this.x = x;
    }
}

class Loophole {

    public static <T> T[] array(final T... values) {
        return (values);
    }

    public static void main(String[] args) {

        Box<String> a = new Box("Hello");
        Box<String> b = new Box("World");
        Box<String> c = new Box("!!!!!!!!!!!");
        Box<String>[] bsa = array(a, b, c);
        System.out.println("I created an array of generics.");

        Object[] oa = bsa;
        oa[0] = new Box<Integer>(3);
        System.out.println("error not caught by array store check");

        try {
            String s = bsa[0].x;
        } catch (ClassCastException cause) {
            System.out.println("BOOM!");
            cause.printStackTrace();
        }
    }
}

출력은

I created an array of generics.
error not caught by array store check
BOOM!
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at Loophole.main(Box.java:26)

그래서 자바에서 일반 배열 유형을 만들 수있는 것처럼 보입니다. 질문을 오해 했습니까?


귀하의 예는 내가 요청한 것과 다릅니다. 배열 공분산의 위험에 대해 설명했습니다. 확인해보십시오 (.NET의 경우 : blogs.msdn.com/b/ericlippert/archive/2007/10/17/… )
삼킨 elysium

컴파일러에서 타입 안전 경고를 받으십시오.
Matt McHenry

1
예, 타입 안전 경고가 나타납니다. 그렇습니다. 제 모범이 그 질문에 반응하지 않는 것을 보았습니다.
emory

실제로 a, b, c의 조잡한 초기화로 인해 여러 경고가 나타납니다. 또한 이것은 잘 알려져 있으며 <T> java.util.Arrays.asList (T ...)와 같은 핵심 라이브러리에 영향을줍니다. T에 대해 수정 불가능한 유형을 전달하면 (생성 된 배열이 코드보다 덜 정확한 유형이기 때문에) 경고가 표시되며 매우 추악합니다. 이 메소드 의 작성자 가 안전하다고 가정 할 때,이 메소드 의 작성자 가 사용 사이트에서 경고를 보내는 대신 경고를받는 것이 더 나을 것 입니다. 메소드는 사용자에게 노출되지 않습니다.
Dimitris Andreou

1
여기에 일반 배열을 만들지 않았습니다. 컴파일러가 제네릭이 아닌 배열을 생성했습니다.
newacct

2

나는 여기서 파티에 조금 늦었다는 것을 알고 있지만,이 답변 중 어느 것도 내 문제를 해결하지 못했기 때문에 미래의 Google 직원을 도울 수있을 것이라고 생각했습니다. Ferdi265의 답변은 엄청난 도움이되었습니다.

내 자신의 연결 목록을 만들려고하므로 다음 코드가 저에게 효과적입니다.

package myList;
import java.lang.reflect.Array;

public class MyList<TYPE>  {

    private Node<TYPE> header = null;

    public void clear() {   header = null;  }

    public void add(TYPE t) {   header = new Node<TYPE>(t,header);    }

    public TYPE get(int position) {  return getNode(position).getObject();  }

    @SuppressWarnings("unchecked")
    public TYPE[] toArray() {       
        TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());        
        for(int i=0 ; i<size() ; i++)   result[i] = get(i); 
        return result;
    }


    public int size(){
         int i = 0;   
         Node<TYPE> current = header;
         while(current != null) {   
           current = current.getNext();
           i++;
        }
        return i;
    }  

toArray () 메서드에는 제네릭 형식의 배열을 만드는 방법이 있습니다.

TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());    

2

필자의 경우 단순히 다음과 같은 스택 배열을 원했습니다.

Stack<SomeType>[] stacks = new Stack<SomeType>[2];

이것이 불가능했기 때문에 다음을 해결 방법으로 사용했습니다.

  1. 스택 주위에 제네릭이 아닌 래퍼 클래스를 만들었습니다 (예 : MyStack).
  2. MyStack [] 스택 = 새로운 MyStack [2]가 완벽하게 작동했습니다

추악하지만 Java는 행복합니다.

참고 : 질문에 대한 의견에서 BrainSlugs83에서 언급했듯이 .NET에서 제네릭 배열을 가질 수 있습니다.


2

에서 오라클 튜토리얼 :

매개 변수화 된 유형의 배열을 작성할 수 없습니다. 예를 들어 다음 코드는 컴파일되지 않습니다.

List<Integer>[] arrayOfLists = new List<Integer>[2];  // compile-time error

다음 코드는 다른 유형이 배열에 삽입 될 때 발생하는 상황을 보여줍니다.

Object[] strings = new String[2];
strings[0] = "hi";   // OK
strings[1] = 100;    // An ArrayStoreException is thrown.

일반 목록으로 같은 것을 시도하면 문제가 있습니다.

Object[] stringLists = new List<String>[];  // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>();   // OK
stringLists[1] = new ArrayList<Integer>();  // An ArrayStoreException should be thrown,
                                            // but the runtime can't detect it.

매개 변수화 된 목록의 배열이 허용 된 경우 이전 코드는 원하는 ArrayStoreException을 발생시키지 않습니다.

나에게 그것은 매우 약하게 들린다. 나는 제네릭을 충분히 이해하고 있다면 완벽하게 괜찮을 것이라고 생각하며 심지어 그러한 경우 ArrayStoredException이 발생하지 않을 것이라고 생각합니다.


0

분명히 그 주위에 좋은 방법이 있어야합니다 (반사를 사용하고있을 수도 있습니다) ArrayList.toArray(T[] a). 나는 인용한다 :

public <T> T[] toArray(T[] a)

이리스트 내의 모든 요소를 ​​포함한 순서를 올바른 순서로 돌려줍니다. 리턴 된 배열의 런타임 유형은 지정된 배열의 런타임 유형입니다. 목록이 지정된 배열에 맞는 경우 반환됩니다. 그렇지 않으면 지정된 배열의 런타임 유형과이 목록의 크기로 새 배열이 할당됩니다.

따라서 한 가지 방법은이 함수를 사용하는 것입니다. 즉 ArrayList배열에 원하는 객체를 만든 다음toArray(T[] a) 실제 배열을 만드는 데 합니다. 빠르지는 않지만 요구 사항에 대해서는 언급하지 않았습니다.

누구나 toArray(T[] a)구현 방법을 알고 있습니까?


3
List.toArray (T [])는 런타임에 기본적으로 구성 요소 유형 T를 제공하기 때문에 작동합니다 (배열 클래스를 가져올 수있는 원하는 배열 유형의 인스턴스를 제공 한 다음 구성 요소 클래스 T ). 런타임에 실제 구성 요소 유형을 사용하면 항상을 사용하여 해당 런타임 유형의 배열을 작성할 수 있습니다 Array.newInstance(). 컴파일 타임에 알 수없는 유형의 배열을 만드는 방법을 묻는 많은 질문에 언급 된 것을 찾을 수 있습니다. 그러나 OP는 구문을 사용할 수없는 이유 를 구체적으로 묻고있었습니다 new T[]. 이는 다른 질문입니다
newacct

0

그것은 제네릭이 자바에 추가 된 후에 자바에 추가 되었기 때문에, 원래의 자바 제작자는 배열을 만들 때 유형을 만들 때 유형이 지정 될 것이라고 생각했기 때문에 어색합니다. 따라서 제네릭에서는 작동하지 않으므로 E [] array = (E []) new Object [15]; 컴파일되지만 경고가 표시됩니다.


0

일반 배열을 인스턴스화 할 수없는 경우 왜 언어에 일반 배열 유형이 있습니까? 객체가없는 유형의 요점은 무엇입니까?

내가 생각할 수있는 유일한 이유는 varargs foo(T...)입니다. 그렇지 않으면 일반 배열 유형을 완전히 제거 할 수 있습니다. varargs가 1.5 이전에는 존재하지 않았기 때문에 varargs에 실제로 배열을 사용할 필요는 없었습니다. . 아마도 다른 실수 일 것입니다.

거짓말이야, 넌 할 수있어 varargs를 통해 일반 배열을 인스턴스화 !

물론 일반적인 배열의 문제는 여전히 실제입니다.

static <T> T[] foo(T... args){
    return args;
}
static <T> T[] foo2(T a1, T a2){
    return foo(a1, a2);
}

public static void main(String[] args){
    String[] x2 = foo2("a", "b"); // heap pollution!
}

이 예제를 사용하여 실제로 일반 배열 의 위험을 보여줄 수 있습니다 .

반면에, 우리는 10 년 동안 일반적인 varargs를 사용해 왔으며 하늘은 아직 떨어지지 않습니다. 따라서 우리는 문제가 과장되었다고 주장 할 수 있습니다. 큰 문제가 아닙니다. 명시적인 일반 배열 생성이 허용되면 여기저기서 버그가 발생합니다. 그러나 우리는 소거의 문제에 익숙해 져 있으며, 그와 함께 살 수 있습니다.

그리고 우리는 foo2스펙이 우리를 막아주는 문제로부터 우리를 지켜 준다는 주장을 반박 할 수 있습니다 . 만약 썬이 1.5 시간 동안 더 많은 시간과 자원을 가지고 있다면 더 만족스러운 해결책에 도달 할 수 있다고 생각합니다.


0

다른 사람들이 이미 언급했듯이 물론 몇 가지 트릭을 통해 만들 수 있습니다. .

그러나 권장하지 않습니다.

때문에 유형 삭제 더 중요한 것은 covariance단지 하위 배열을 허용 배열은 런타임의 원인이 값 다시 얻을하려고 할 때 명시 적 유형 캐스트를 사용하는 힘 슈퍼 배열에 할당 할 수 있습니다 ClassCastException주요 목표 중 하나입니다 그 제네릭은 제거하려고합니다 : 컴파일시 더 강력한 유형 검사 .

Object[] stringArray = { "hi", "me" };
stringArray[1] = 1;
String aString = (String) stringArray[1]; // boom! the TypeCastException

보다 직접적인 예제는 Effective Java : Item 25 에서 찾을 수 있습니다 .


공분산 : S [] 유형의 배열은 S가 T의 하위 유형 인 경우 T []의 하위 유형입니다.


0

클래스가 매개 변수화 된 형식으로 사용되는 경우 T [] 형식의 배열을 선언 할 수 있지만 이러한 배열을 직접 인스턴스화 할 수는 없습니다. 대신 일반적인 접근 방식은 Object [] 유형의 배열을 인스턴스화 한 후 다음과 같이 T [] 유형으로 범위를 좁히는 것입니다.

  public class Portfolio<T> {
  T[] data;
 public Portfolio(int capacity) {
   data = new T[capacity];                 // illegal; compiler error
   data = (T[]) new Object[capacity];      // legal, but compiler warning
 }
 public T get(int index) { return data[index]; }
 public void set(int index, T element) { data[index] = element; }
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.