了解 的上限和下限?在 Java 泛型中

2022-09-01 06:08:44

我真的很难理解通配符参数。我对此有几个问题。

  1. ?作为类型参数,只能在方法中使用。例如:我无法使用 as type 参数定义类。printAll(MyList<? extends Serializable>)?

  2. 我了解 的上限。 意思是:“printAll将打印MyList,如果它具有实现可序列化接口的对象
    我对 . 意思是:“printAll将打印MyList,如果它有MyClass或任何扩展MyClass的类(MyClass的后代)的对象。?printAll(MyList<? extends Serializable>)superprintAll(MyList<? super MyClass>)"

纠正我哪里错了。

简而言之,只有 TEKVN 可以用作定义泛型类的类型参数。只能用于方法


更新 1:
public void printAll(MyList<? super MyClass>){
    // code code code
}

与Ivor Horton的书一致,意味着如果它有它实现的对象或任何接口或类,我可以打印。也就是说,是一个下限。它是继承层次结构中的最后一个类。这意味着我最初的假设是错误的。MyList<? super MyClass>MyListMyClassMyClass

所以,假设看起来像这样:MyClass

public class MyClass extends Thread implements ActionListener{
    // whatever
}

然后,如果
1,将打印。列表
2 中有 的对象。有 对象 或 在printAll()MyClassThreadActionListenerList


更新 2:

因此,在阅读了该问题的许多答案之后,以下是我的理解:

  1. ? extends T表示扩展 T 的任何类。因此,我们指的是T的子。因此,T 是上限。继承层次结构中的最上层阶级

  2. ? super T表示任何/接口是 T 的超级。因此,我们指的是T的所有父级因此,T 是下限。继承层次结构中最低的类


答案 1

?作为类型参数,只能在方法中使用。例如:我无法使用 as type 参数定义类。printAll(MyList<? extends Serializable>)?

通配符 () 不是正式的类型参数,而是可以用作类型参数。在你给出的示例中,作为泛型类型 ,给出的方法参数的参数。?? extends SerializableMyListprintAll

方法还可以像类一样声明类型参数,例如:

static <T extends Serializable> void printAll(MyList<T> myList)

我了解 的上限。 意味着 printAll 将打印 MyList,如果它具有实现可序列化接口的对象?printAll(MyList<? extends Serializable>)

更准确地说,这意味着printAll 的调用只有在传递给具有某些可序列化或实现的泛型类型的 MyList 时才会编译。在这种情况下,它将接受一个 、 等。MyList<Serializable>MyList<Integer>

我对 . 意味着 printAll 将打印 MyList,如果它具有 MyClass 或任何扩展 MyClass 的类(MyClass 的后代)的对象superprintAll(MyList<? super MyClass>)

以 为界的通配符是限。因此,我们可以说,只有当向 MyList 传递了一个 MyList,其中包含一些通用类型 MyClass 或某个超类型的 MyClass 时,才会编译对 printAll 的调用。因此,在这种情况下,它将接受MyList<MyClass>,例如MyList<MyParentClass>MyList<Object>super

所以,假设MyClass看起来像这样:

public class MyClass extends Thread implements ActionListener{
    // whatever
}

然后,printAll() 将在以下情况下打印:

  1. 列表中有 MyClass 的对象
  2. 列表中有线程或操作Listener的对象

您走在正确的轨道上。但我认为,例如说“如果列表中有对象,它将打印”是有问题的。这听起来像是在定义运行时行为 - 泛型都是关于编译时检查的。例如,无法通过继承将 a 作为 的参数传递,即使它可能包含 的实例。我会把它改写成:MyClassMyList<MySubclass>MyList<? super MyClass>MyClass

仅当传递了以下各项时,对 的调用才会编译:printAll(MyList<? super MyClass>)

  1. MyList<MyClass>
  2. MyList<Thread>
  3. MyList<Runnable>
  4. MyList<ActionListener>
  5. MyList<EventListener>
  6. MyList<Object>
  7. MyList<? super X>其中 为 、 、 、 、 或 。XMyClassThreadRunnableActionListenerEventListenerObject

因此,在阅读了该问题的许多答案之后,以下是我的理解:

? extends T表示扩展 T 的任何类。因此,我们指的是T的子项,因此,T是上限。继承层次结构中的最上层阶级

? super T表示属于 T 的任何类/接口。因此,我们指的是T的所有父项,因此T是下限。继承层次结构中最低的类super

接近,但我不会说“子项”或“父母”,因为这些界限是包容性的 - 更准确地说“或其亚型”和“或其超型”。TTTT


答案 2

首先,或或或任何东西都不是固定的名称。它们只是类型变量,由您决定它们的名称。,,只是例子,但你可以称之为什么。TEKTEKFoo

现在转到第一个问题:由于通配符表示“any and unknown”类型,即未指定的类型,因此在未指定的类型上声明类泛型没有任何意义。在不关心类型时,在方法参数或变量中使用通配符很有用。?

现在关于你的第二个问题:下限给你的泛型方法提供了更大的灵活性。两者都相反:extendssuper

  • ? extends T:一种未知类型,它是T
  • ? super T:一种未知类型,它是T

当您想要接受与 T 兼容的类型(以便 T 是该类型)时,后者可能很有用。一个实际的例子可以在这里找到。


推荐