2012-05-02 3 views
15

제네릭 클래스를 배열 또는 더 나은 기본 배열로 지정해야합니다. 지금까지 내가 일한 것입니다 :자바 일반 및 배열 유형 (예 : 제네릭 유형의 배열)

interface Foo<T> { 
    void process(T data); 
} 

public class Moo implements Foo<int[]> { 
    void process(int[] data) { 
    // do stuff here 
    } 
} 

원시적 인 배열이 Object를 확장하기 때문에 이것은 모두 완벽하게 유효한 Java 코드이며 작동합니다. 이 질문은 완전히 다른입니다. 다른 Java 배열의 일반적인 질문과 마찬가지로 계속 찾습니다. 이 상황에서 사람들은 일반적인 유형의 배열을 만들고 싶어합니다.

문제는 Type T는 Object를 확장하는 모든 것이 될 수 있다는 것입니다. 내가 원하는 것은 같은 것을하는 것입니다 :

<T extends ONLY ARRAYS> 

또는

<T extends ONLY PRIMITIVE ARRAYS>. 

을하는 것이 가능합니까?

EDIT : 최종 목표는 전달되는 배열 유형에 대한 컴파일 시간 검사를 추가하는 것입니다. 지금은 모든 이전 객체를 전달할 수 있으며 잘 컴파일됩니다. 실수는 클래스 캐스트 예외가 발생하는 런타임에만 발견됩니다. 사실 이것은 컴파일 타임 타입 검사를 강화하기 위해 Java의 Generics 전체 요점입니다.

+2

이 왜 이렇게해야 T.의 배열로 형태를 돌려하려면? – Jeffrey

+0

나는 "가능하다"고 동의한다. 내 직감은 Object보다 primitive-classes 배열의 다른 상위 유형이 없다고합니다. (클래스 클래스에는 isArray()가 있습니다. – esej

+0

서로 다른 기본 유형의 데이터로 이미지를 처리하기위한 단일 인터페이스입니다. 대안은 각 유형에 대해 다른 인터페이스를 갖는 것인데, 이는 더 나쁜 kludge입니다. 예제, Foo_S32, Foo_U8, Foo_F32, ... 등. –

답변

10

수행 할 수 없습니다. 어떤 클래스도 배열을 확장 할 수 없으므로 generic 매개 변수 T extends Object[]을 만족하는 유형은 없습니다. (. 다른 것보다 Object[] 자체를,하지만 당신이 제네릭을 사용하지 않는 것)

당신이 할 수있는 것은이 같은 것입니다 :

public interface Foo<T extends Number> { 
    public void process(T[] data); 
} 

을하지만 당신은 복싱 성능 문제로 실행될 수 있습니다.

+4

String []과 같은 특정 유형의 배열은 Object []에 할당 가능합니다. 그러나 이것은 원시 배열에 도움이되지 않습니다. –

+1

@StevenSchlansker 내가 제공 한 예제는 어쨌든 헛수고인데, 배열을 타입 매개 변수 바운드로 사용할 수 없습니다. – Jeffrey

+0

대체 접근법으로 성능이 저하 될 수도 있습니다. 좀 더 검색을 한 후에는 원하는 제약 조건을 허용하는 특수 언어 예외를 찾을 수 없습니다. 귀하가 정답을 처음으로 제시 한 이래로 이것을 해결책으로 선택하십시오. –

1

아니요.

자바에서
public class SOTEST {  
    public static void main(String[] args) throws Exception { 
     int[] arr = new int[] {}; 
     Class c = arr.getClass(); 
     for(Class clazz:c.getInterfaces()) { 
      System.out.println(clazz.getName()); 
     } 

     System.out.println(c.getSuperclass().toString()); 
    } 
} 
8

입력 매개 변수가 only 서브 타입 관계에 의해 제약 및 모든 배열 areObject, Clonable의 유일한 공통의 슈퍼 타입 할 수 없음 "흥미로운"인터페이스도 어떤 슈퍼 그러나 개체 프리미티브의 배열을 위해 존재하지 않는다 Serializable. 당신이 얻을 수있는 가장 가까운 자바 않은 경우에도

... Integer[], Long[]의 슈퍼 타입이 아닌 기본 구성 요소 유형, 또는 가능성에 Number[] 모든 배열의 슈퍼 타입이, 인, Object[]로 제한하는 것입니다 그러한 제약 조건을 지원한다면, 어떻게 그 배열에 유용한 것을 할 수 있을까요? 배열 요소에 할당 할 수있는 표현식을 적을 수 없기 때문에 결과를 저장할 변수를 선언 할 수 없으며 개별 요소를 작성할 수 없으므로 개별 요소를 읽을 수 없습니다. 내가 구성 요소 유형으로 유형 변수를 결합이라고 말했다

, 아닌 배열 유형 :

interface Foo<T extends Whatever> { 
    void process(T[] data); 
} 

당신이 T을 알고 T[]를 참조 할 수 있기 때문에,하지만 T extends Object[]을 아는 것이 바로 당신을 허용하지 않습니다 구성 요소 유형을 참조하십시오.

편집 : 제프리가 제대로 당신은 확실히 <T extends Whatever> 선언의 내 충고를 따라 배열 형식을 참조하는 T[]를 사용해야하므로 즉 <T extends Whatever[]>는 컴파일되지 않습니다, 그 배열 유형이 유형의 범위에서 사용할 수 없습니다 지적했다.

+0

제약 조건을 추가하고자하는 요점은 일반화 된 클래스가 배열을 조작하여 작성 될 수는 없지만 API를보다 쉽게 ​​사용할 수 있도록하기 위해서입니다. 지금은 컴파일 시간 검사가없고 런타임에 오류 만 잡힐 것입니다. –

-2

X의 배열에는 유형 계층이 없습니다. 정수 []는 Number []의 하위 클래스가 아닙니다.

당신이 원하는 당신의 유형 매개 변수 T로 배열 구성 요소 유형을 사용하는 것을 얻을 수 및 매개 변수를 선언하고

+0

-1 잘못된 정보 :'Integer []'*는'Number []'의 부속 유형입니다. 예를 들어,'Number [] numbers = new Integer [] {1, 2, 3};은 단지 잘 컴파일됩니다 ... – meriton

+0

글쎄 - 그게 너트이고 자바 타입 시스템의 구멍입니다. 이 \t 정수 [] ints = 새로운 정수 [] {1, 2, 3}; \t Number [] numbers = ints; \t numbers [1] = 새로운 부동 소수 (4); \t (int x : ints) { \t \t System.out.println (x); \t} 을 컴파일하고 런타임에 ArrayStoreException을 발생시킵니다. – PaulMurrayCbr

+1

예, 배열의 공분산은 liskov 대체 가능성을 위반합니다 (JLS와 마찬가지로 배열 계약의 일부로 ArrayStoreExceptions을 처리하지 않는 한). 그러나 런타임 검사는 런타임시 Java가 유형 안전성을 유지하도록 보장합니다. "너트"에 관해서는 당신의 견해가 확실하지만, 타입 시스템의 허점에만 초점을 맞추는 것은 다소 제한된 견해라고 생각합니다. 배열은 공변이며 런타임에 검사됩니다. generics는 각 사용 사이트에서 공분산해야하며 런타임에 확인되지 않습니다 (실제로 힙 손상을 가능하게합니다). 더 좋은 디자인은 무엇입니까? – meriton