Java Generic 메소드를 정적으로 만드는 방법은 무엇입니까?


172

다음은 단일 항목을 배열에 추가하기 위해 Java 일반 클래스를 작성하는 방법에 대한 스 니펫입니다. appendToArray를 정적 메서드로 만들려면 어떻게해야합니까? 메소드 서명에 정적을 추가하면 컴파일 오류가 발생합니다.

public class ArrayUtils<E> {

        public E[] appendToArray(E[] array, E item) {
            E[] result = (E[])new Object[array.length+1];
            result[array.length] = item;
            return result;
        }
}

어떤 컴파일 오류가 발생합니까? 또한 표준 라이브러리 컨테이너 중 하나만 사용하는 것이 어떻습니까?
Karl Knechtel

1
컴파일 오류 : 실제로 정적 수정자를 잘못 추가했습니다. 컬렉션 사용 : 예를 사용하면 컬렉션을 사용하는 것이 이상적이지만 컬렉션 대 배열에 대한 질문은 아닙니다. 사용 사례에는 배열이 필요합니다.
Chris Johnson

(EVIL) 리플렉션을 사용하여 일부 상황에서는 예외를 발생시키는 클라이언트 코드를 중지해야합니다 (일부). 참조 배열을 피하는 것이 가장 좋습니다.
Tom Hawtin-tackline

답변:


283

당신이 할 수있는 유일한 일은 서명을

public static <E> E[] appendToArray(E[] array, E item)

중요한 세부 사항 :

반환 값 앞에 오는 제네릭 식은 항상 새로운 제네릭 형식 변수를 도입 (선언)합니다.

또한 형식 ( ArrayUtils)과 정적 메서드 ( appendToArray) 사이의 형식 변수는 서로 간섭하지 않습니다.

그래서 이것이 의미하는 바는 : 내 대답 에서 메소드가 아닌 경우 from을 <E>숨길 것 입니다. 그리고 from 과 는 아무런 관련이 없습니다 .EArrayUtils<E>static<E>EArrayUtils<E>

이 사실을 더 잘 반영하기 위해 더 정확한 답은 다음과 같습니다.

public static <I> I[] appendToArray(I[] array, I item)

30
또한 클래스 수준 유형 변수 E와 정적 메서드 유형 변수 사이에는 아무런 관계가 없습니다 E. 제네릭 클래스 내부에서 정적 또는 다른 방식으로 제네릭 메서드를 선언 할 때 다른 변수 이름을 사용하는 것이 훨씬 더 좋습니다.
판사 정신

그러나이 경우 다른 유형의 객체 하나를 매개 변수에 전달할 수 있습니다. 내가 Integer [] 배열을 첫 번째 param과 Double 항목으로 전달할 수있는 것처럼.
pinkpanther

pinkpanther : 정적 메소드는 매개 변수를 통해 전달 된 배열 객체에서만 작동하므로 요소의 유형이 올바른지 확인해야합니다.
Dabbler

80
public static <E> E[] appendToArray(E[] array, E item) { ...

를 참고하십시오 <E>.

정적 제네릭 메서드 public static <E>에는 클래스의 제네릭 선언 ( public class ArrayUtils<E>)과 별개로 고유 한 제네릭 선언 ( )이 필요합니다 .

컴파일러가 정적 제네릭 메서드를 호출하는 데있어 모호한 유형에 대해 불평하는 경우 (여러분의 경우는 아니지만 일반적으로 말하면) 특정 유형 ( _class_.<_generictypeparams_>_methodname_)을 사용하여 정적 제네릭 메서드를 명시 적으로 호출하는 방법은 다음과 같습니다.

String[] newStrings = ArrayUtils.<String>appendToArray(strings, "another string");

예를 들어 제네릭 형식은 메서드 인수와 관련이 없기 때문에 컴파일러가 제네릭 형식을 확인할 수없는 경우에만 발생합니다.


10

제네릭 클래스가 아닌 제네릭 메서드가 있음을 나타내려면 형식 매개 변수를 메서드 수준으로 이동해야합니다.

public class ArrayUtils {
    public static <T> E[] appendToArray(E[] array, E item) {
        E[] result = (E[])new Object[array.length+1];
        result[array.length] = item;
        return result;
    }
}

1
제네릭 형식 E를 정의하지 않았기 때문에 작동하지 않습니다.이 경우 클래스 정의에 여전히 제네릭 형식 <E>가 있어야합니다.
George Xavier

0

간단한 방법으로 설명하겠습니다.

클래스 수준에서 정의 된 제네릭은 (정적) 메서드 수준에서 정의 된 제네릭과 완전히 분리됩니다.

class Greet<T> {

    public static <T> void sayHello(T obj) {
        System.out.println("Hello " + obj);
    }
}

위 코드를 어디에서나 볼 때 클래스 수준에서 정의 된 T는 정적 메서드에서 정의 된 T와 아무 관련이 없습니다. 다음 코드는 완전히 유효하며 위 코드와 동일합니다.

class Greet<T> {

    public static <E> void sayHello(E obj) {
        System.out.println("Hello " + obj);
    }
}

정적 메소드에 클래스와 다른 고유 한 제네릭이 필요한 이유는 무엇입니까?

클래스를 인스턴스화하지 않고도 정적 메소드를 호출 할 수 있기 때문입니다. 따라서 클래스가 아직 인스턴스화되지 않은 경우 아직 T가 무엇인지 알 수 없습니다. 이것이 정적 메소드에 고유 한 제네릭이 필요한 이유입니다.

따라서 정적 메소드를 호출 할 때마다

Greet.sayHello("Bob");
Greet.sayHello(123);

JVM은이를 다음과 같이 해석합니다.

Greet.<String>sayHello("Bob");
Greet.<Integer>sayHello(123);

둘 다 동일한 출력을 제공합니다.

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