如何正确使用类型参数

时间:2016-09-15 14:13:21

标签: java

我对类型参数感到困惑。在下面的代码中,CollectionData尖括号内的类型可以称为类型参数。 ArrayList和Generator中的类型不是类型参数,在CollectionData中应该是相同的。如何理解?

//correct
public class CollectionData<T> extends ArrayList<T> {
    CollectionData(Generator<T> generator) {

    }
}

interface Generator<E> {
    E next();
}

以下是错误的。但有时我无法帮助写这篇文章。

// wrong
public class CollectionData<T> extends ArrayList<E> {
    CollectionData(Generator<W> generator) {

    }
}

interface Generator<E> {
    E next();
}

已添加
在上面的示例中,类型变量只能在CollectionData的尖括号中定义,而不是在ArrayList或Generator中定义?然后ArrayList和CollectionData使用这些类型。正确?

3 个答案:

答案 0 :(得分:3)

这些泛型类型只是类型变量

书写

public class CollectionData<T> extends ArrayList<E> {

类似于写作

public int func(int x) {
     return y;
}

如果没有变量y,则此代码错误。 但由于您声明了x,因此您可以在适当情况下使用x

public int func(int x) {
     return x;
}

通用类型也是如此。 当你写

public class CollectionData<T> extends ArrayList<T>

你是说T里面的ArrayList<T>相同的 T,由你的类的泛型类型参数给出。 构造函数的参数类型也是如此。

所以,为了帮助你知道何时写出&#34;正确&#34;代码:如果您要求两个泛型类型相同(例如,为类提供的泛型类型,基类的泛型类型或函数的参数),则必须使用相同的类型变量。 当您需要存储在该变量中的确切值时,这与在函数内使用相同变量的情况相同。

编辑您的附录:

泛型类型只能在类名上声明:

public class CollectionData<T> extends ArrayList<E>

声明T,但只有使用 E。当然,这要求E已被声明为某种类型的泛型类型(或类)。 (当E是泛型类型时,只有当CollectionData<T>位于声明E的外部类中时,这才有效。)

当然,也可以为每个函数声明泛型类型:

public <T> void foo(T x) { x.baz(); }

声明 T阴影 T的任何定义。 例如,在此上下文中

public class Foo<T> {
    public <T> void foo(T x) { x.baz(); }
}

T方法中的foo T声明的Foo。 这又像阴影变量一样有效:

public class Foo {
    int x;
    public int foo(int x) {
        // returns x from argument, not the field of the class
        return x;
    }
}

答案 1 :(得分:1)

我将假设您正在尝试使用构造函数中CollectionData传入的内容填充Generator个实例。

需要匹配时,需要使用相同的类型参数。在您的第一个示例中,CollectionData中的所有类型参数均为T。由于它们具有相同的标识符,因此编译器知道它们必须匹配。

在第二个示例中,您有类型参数TWE。这不起作用,因为您无法使用E的实例填充TW的列表。编译器无法知道实例类型是否兼容。

答案 2 :(得分:1)

我认为导致你的混淆的是定义泛型类型和使用之间的区别。

定义泛型类型基本上就像定义一个函数 - 你定义它的参数以及它如何使用它的参数。

使用泛型类型意味着它必须完全可以被编译器理解 - 它不能依赖于尚未定义的类型。

此处,在您的示例中,定义以单词extends结尾。接下来的所有内容都使用泛型类型,因此除了定义标题中的类型参数外,不能使用未知的类型。功能定义的类比应该有助于消除混淆。