有人在评论中说,问题正在引起混乱。所以,我已经编辑了这个问题,让我知道,如果它仍然引起混乱。
考虑以下代码:
班级雇员{}
Class ContractEmployee类扩展Employee { }
PermanentEmployee类扩展了Employee { } ...
谁能提供以下两种情况之间的基本区别? 何时使用哪个
情况:1
public <T extends Employee> void empTest(ArrayList<T> list)
public <? extends Employee> void empTest(ArrayList<?> list)
情况:2
public void empTest(ArrayList<? extends Employee> list)
public void empTest(ArrayList<T extends Employee> list)
答案 0 :(得分:0)
没有完整的解释,但您将从这里开始。我们需要在泛型中遵循PECS模式。 PECS代表 P 引纸器 E xtends和 C 消费方 S 上方。
在下面的行中,
public void empTest(ArrayList列表)
您基本上是在提供列表,该列表将在该方法内进一步用作生产者。现在,您可能知道,泛型只是编译时的错觉,并且会在运行时删除,因此mrthod empTest中的代码期望使用特定Employee的列表。例如,如果您将Fruit作为Orange和Apple的超类,则不应向消费者提供Orange和Apple的列表,而不能将其限制为Apple或Orange。是否有意义?我猜是。
答案 1 :(得分:0)
首先,您的问题是很合理的,尽管通过您的示例,很难解释/理解差异。
在所有变体中,您都想定义一个方法empTest()
,该方法接受Employee的ArrayList或Employee的子类。您可以使用
public void empTest(ArrayList<? extends Employee> list) { ... }
那么,其他语法变体又意味着什么呢?我们使用另一个示例,因为您的empTest()
方法不需要其他任何东西。
说,我们想使用类似addEmp(list, emp);
的方式将员工添加到列表中。第一个想法可能是:
public void addEmp(ArrayList<Employee> list, Employee emp) { ... }
但是那样做不会做,因为您将无法将ArrayList<ContractEmployee>
传递给方法。下次尝试:
public void addEmp(ArrayList<? extends Employee> list, Employee emp) { ... }
现在它接受列表,但是它还允许您将ArrayList<ContractEmployee>
与PermanentEmployee
组合使用,并且不能将PermanentEmployee
添加到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
参数列表。关于语法: -如果您需要为type参数引入名称,请在返回类型之前完成。 -在方法返回类型或方法参数列表中,您只能使用已经存在的名称,或使用未命名的通配符构造。