2 回答
TA贡献1775条经验 获得超8个赞
首先,您的问题非常合理,尽管通过您的示例,很难解释/理解这些差异。
在所有变体中,您都希望定义一个方法empTest()
来接受雇员的 ArrayList 或雇员的子类。你这样做
public void empTest(ArrayList<? extends Employee> list) { ... }
那么,其他语法变体的用途是什么?让我们使用不同的示例,因为您的empTest()
方法不需要任何其他内容。
比如说,我们想使用类似addEmp(list, emp);
. 第一个想法可能是:
public void addEmp(ArrayList<Employee> list, Employee emp) { ... }
但这不会完成这项工作,因为您将无法将 an 传递ArrayList<ContractEmployee>
到方法中。下一次尝试:
public void addEmp(ArrayList<? extends Employee> list, Employee emp) { ... }
现在它接受列表,但它也允许您将 aArrayList<ContractEmployee>
与 a 组合传递PermanentEmployee
,并且不允许将 a 添加PermanentEmployee
到 an ArrayList<ContractEmployee>
。编译器会将方法主体中添加员工的行标记为非法。
所以,我们在这里需要的是检查在两个地方使用相同类型的员工,这就是命名类型参数可以用来做什么。
public <T extends Employee> void addEmp(ArrayList<T> list, T emp) { ... }
这表示:可以传入ArrayList
的任何子类型中的Employee
,我们称之为子类型T
。然后emp
参数也必须来自相同的子类型T
(或由于正常的类继承而来自子子类型)。
如果是Employee
与否对方法没有影响,你甚至可以写
public <T> void addEmp(ArrayList<T> list, T emp) { ... }
总结一下:
<... extends SomeClass>
如果需要比普通<SomeClass>
构造更多的可变性,请使用构造。如果它只是您需要可变性的一个地方,通常不需要为子类引入名称,因此
<? extends SomeClass>
在方法的参数列表中即可完成这项工作。如果你需要在多个地方使用相同的子类,你需要给它一个名字,所以
<T extends SomeClass>
在返回类型声明前面使用类似的东西,并且T
在参数列表中使用不带尖括号的东西。
关于语法: - 如果您需要为类型参数引入名称,则在返回类型之前完成。- 在方法返回类型或方法参数列表中,您只能使用已存在的名称,或使用未命名的通配符构造。
TA贡献1804条经验 获得超7个赞
不完整的解释,但你会从这里开始。我们需要在泛型中遵循PECS模式。佩奇表示P roducer Ë xtends和ç onsumer小号UPER。
在您下面的行中,
public void empTest(ArrayList list)
您基本上是在提供列表,该列表将作为生产者在该方法中进一步使用。现在您可能知道,泛型只是编译时的错觉,会在运行时被删除,您在 mrthod empTest 中的代码期待特定员工的列表。例如,如果您将 Fruit 作为 Orange 和 Apple 的超类,则不应将 Orange 和 Apple 的列表同时提供给消费者并将其限制为 Apple 或 Orange。是否有意义?我猜是。
添加回答
举报