如何使Java泛型方法静态?


172

以下是有关如何使Java通用类将单个项目附加到数组的代码段。如何使appendToArray成为静态方法。在方法签名中添加static会导致编译错误。

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 2010年

1
编译错误:实际上我是错误地添加了静态修饰符。
克里斯·约翰逊

请注意,您需要使用(EVIL)反射来阻止客户端代码在某些(但不是全部)情况下(很好)抛出异常。最好避免引用数组。
汤姆·霍顿

Answers:


283

您唯一可以做的就是将您的签名更改为

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

重要细节:

返回值之前的泛型表达式始终会引入(声明)新的泛型类型变量。

此外,类型(ArrayUtils)和静态方法(appendToArray)之间的类型变量永远不会相互干扰。

因此,这意味着什么:如果方法不是,则我的答案<E>将隐藏。AND 与from 无关。EArrayUtils<E>static<E>EArrayUtils<E>

为了更好地反映这一事实,一个更正确的答案是:

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

30
还请注意,类级别的类型变量E和静态方法类型变量之间绝对没有关系E。我认为在类的内部声明静态或非静态通用方法时,最好使用不同的变量名。
法官Mental

但是在这种情况下,我可以将一个不同类型的对象传递给参数。就像我可以将Integer []数组作为第一个参数和Double项一样传递。
pinkpanther

pinkpanther:是的,但是没有任何害处,因为static方法只对通过参数传递给它的数组对象进行操作,因此它的元素肯定具有正确的类型。
达伯勒

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>。
乔治Xavier

0

我将以简单的方式进行解释。

在类级别定义的泛型与(静态)方法级别定义的泛型完全分开。

class Greet<T> {

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

当您在任何地方看到以上代码时,请注意,在类级别定义的T与static方法中定义的T没有任何关系。以下代码也是完全有效的,并且等效于上述代码。

class Greet<T> {

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

为什么静态方法需要将自己的泛型与Class的泛型分开?

这是因为,即使不实例化Class也可以调用静态方法。因此,如果尚未实例化Class,则我们还不知道T是什么。这就是静态方法需要具有自己的泛型的原因。

因此,无论何时调用静态方法,

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

JVM将其解释为以下内容。

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

两者给出相同的输出。

Hello Bob
Hello 123
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.