2009-04-25 5 views
6

나는 katas 코드를 가지고 놀고 있으며 동시에 java generics에 대해 더 잘 이해하려고 노력 중이다. 나는이 배열을 출력하는 작은 메서드를 가지고 있는데, 배열을 출력하고 싶습니다. 배열을 받아들이고 인덱스 위 또는 아래에있는 'things'의 배열을 반환하는 몇 가지 도우미 메서드가 있습니다 (이진 검색 알고리즘입니다.)int 배열을 java의 제네릭 메소드에 전달할 수 있습니까?

두 질문에,

# 1 난 splitBottom 및 splitTop에서 T로 번지는 현상을 방지 할 수 있습니까? 그것은 기분이 좋지 않거나 잘못된 길로 가고 있습니다. (파이썬이나 무언가를 사용하라고 말하지 마십시오.))

# 2 원시적 인 것들을 다룰 별도의 메소드를 작성해야합니까? 배열 또는 더 나은 솔루션이 있습니까?

public class Util { 

    public static <T> void print(T[] array) { 
     System.out.print("{"); 
     for (int i = 0; i < array.length; i++) { 
      System.out.print(array[i]); 
      if (i < array.length - 1) { 
       System.out.print(", "); 
      } 
     } 
     System.out.println("}"); 
    } 

    public static <T> T[] splitTop(T[] array, int index) { 
     Object[] result = new Object[array.length - index - 1]; 
     System.arraycopy(array, index + 1, result, 0, result.length); 
     return (T[]) result; 
    } 

    public static <T> T[] splitBottom(T[] array, int index) { 
     Object[] result = new Object[index]; 
     System.arraycopy(array, 0, result, 0, index); 
     return (T[]) result; 
    } 

    public static void main(String[] args) { 

     Integer[] integerArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     print(integerArray); 
     print(splitBottom(integerArray, 3)); 
     print(splitTop(integerArray, 3)); 

     String[] stringArray = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"}; 
     print(stringArray); 
     print(splitBottom(stringArray, 3)); 
     print(splitTop(stringArray, 3)); 

     int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     // ??? 
    } 
} 

답변

9

제네릭은 일관된 방식으로 프리미티브를 처리하지 않습니다. Generics는 C++의 템플릿과 닮았지 않기 때문에 단일 클래스에 컴파일 타임을 추가 한 것입니다.

제네릭을 컴파일 할 때 위의 예에서 Object []가 구현 유형으로 끝납니다. int []와 byte [] 등으로 Object []를 확장하지 마십시오. 관련 코드가 동일 할지라도 inter-changeably 사용할 수 없습니다. (제네릭은 템플릿이 아닙니다)

클래스 int []와 Object [] 공유는 Object입니다. 위의 메서드 Object를 형식으로 쓸 수 있습니다 (System.arraycopy, Array.getLength, Array.get, Array.set 참조)

1

질문 1 : 예상대로 캐스팅 배열이 작동하지 않습니다. String는 Object이지만 String 배열은 Object 배열이 아닙니다. 프리미티브의 배열 내 함수를 분명히 중 하나가 작동하지 않는 경우 :

public static <T> T[] splitTop(T[] array, int index) { 
    T[] result = Arrays.copyOfRange(array, index + 1, array.length); 
    return result; 
} 

질문 2 :

봅니다 같은 것을 사용합니다. 우아한 해결책은 없습니다. 예를 들어 각 프리미티브 배열 유형에 대해 본질적으로 동일한 메소드의 여러 복사본이있는 Array 라이브러리를 살펴보십시오.

+0

제네릭으로 할 수 없으므로 호환되지 않는 유형 오류가 발생합니다. – hbw

+0

@htw 자세히 설명해 주시겠습니까? – blank

3

1 splitBottom 및 splitTop에서 T에 대한 캐스트를 피할 수 있습니까?)

당신이 그것을 피할 수 없다뿐만 아니라, 그것은 바로 생각하지 않거나, 나는 ( 파이썬이나 뭐 .. 사용하는 말하지 않는)이 틀린 방법에 대해 갈거야 그러나 당신은 그것을해서는 안됩니다. 자바에서는 배열의 종류가 실제로는 다른 런타임 유형입니다. Object[]으로 작성된 배열은 AnythingElse []의 변수에 할당 할 수 없습니다. generics에서 타입 T가 지워지기 때문에 코드가 즉시 실패하지는 않지만 나중에 코드가 약속대로 그것을 사용하려고 할 때 ClassCastException을 던질 것이지만 그렇지 않다.

해결 방법은 Java 6 이상에서 Arrays.copyOf... 메서드를 사용하거나 이전 버전의 Java를 사용하는 경우 Reflection을 사용하여 올바른 유형의 배열을 만드는 것입니다. 예 :

T [] 결과 = (T []) Array.newInstance (array.getClass().getComponentType(), size);

2 프리미티브 배열을 처리하기 위해 별도의 메서드를 작성해야합니까? 아니면 더 나은 솔루션이 입니까?

별도의 방법을 쓰는 것이 가장 좋습니다. Java에서 기본 유형의 배열은 참조 유형의 배열과 완전히 별개입니다. 그리고 둘 다로 일하는 좋은 방법이 없습니다.

Reflection을 사용하면 두 가지를 동시에 처리 할 수 ​​있습니다. 리플렉션에는 프리미티브 배열과 참조 배열 모두에서 작동하는 Array.get()Array.set() 메서드가 있습니다. 그러나 프리미티브 배열과 참조 배열의 유일한 수퍼 유형이 Object이므로 형식 안전성을 잃게됩니다.

1

Java는 유형이 안전한 방식으로 일반 배열을 구성 할 수 없습니다. 대신 일반 시퀀스 유형을 사용하십시오 (예 : java.util.List). 여기

내가 일반 컨테이너 클래스 fj.data.Stream를 사용하여, 테스트 프로그램을 작성하는 방법은 다음과 같습니다

당신이 달성하기 위해 무엇을하려고하는 두 가지 문제를 가지고
import fj.data.Stream; 
import static fj.data.Stream.range; 

// ... 

public int[] intArray(Stream<Integer> s) { 
    return s.toArray(Integer.class).array() 
} 

public static void main(String[] args) { 
    Stream<Integer> integerStream = range(1, 10); 
    print(intArray(integerStream)); 
    print(intArray(integerStream.take(3))); 
    print(intArray(integerStream.drop(3))); 

    // ... 
} 
0

.

우선, 실제로 Object에서 상속받지 않는 기본 유형을 사용하려고합니다. 이것은 물건을 망칠 것입니다. 정말로 이것을해야한다면, int가 아닌 Integer를 명시 적으로 사용하십시오.

두 번째 및 더 큰 문제는 Java 제네릭이 형식 지움을 가지고 있다는 것입니다. 즉, 런타임에는 실제로 제네릭의 유형을 참조 할 수 없습니다. 이것은 제네릭 지원 및 비 제너릭 지원 코드를 혼합 할 수 있도록하기 위해 이루어졌으며 Java 개발자를위한 주요 골칫거리 인 IMHO와 제네릭이 Java에서 제 1 일 이후에 있어야한다는 또 다른 증거가되었습니다. 그것에 관한 tutorial의 파트를 읽으면,이 문제가 더 명확해질 것입니다.

0

아마도 해당 프리미티브를 해당 컬렉션으로 래핑해야합니다.

원시 기본 컬렉션 (http://trove.starlight-systems.com)을 살펴 보시기 바랍니다. 이것은 귀하의 제네릭 질문과 관련이 없지만 매우 흥미로울 수 있습니다.

관련 문제