ale*_*gen 6 c# java polymorphism foreach
我有一个问题,我没有找到答案.假设我们在java或c#中有以下代码:
class Car {
/* car stuff */
}
Run Code Online (Sandbox Code Playgroud)
然后在Java中
class Truck extends Car {
/* truck stuff */
}
Run Code Online (Sandbox Code Playgroud)
和C#
class Truck : Car {
/* truck stuff again */
}
Run Code Online (Sandbox Code Playgroud)
在C#中,以下工作正常:
List<Car> carList = new List<Car>();
//add some objects to the collection
foreach(Truck t in carList)
//do stuff with only the Truck objects in the carList collection
Run Code Online (Sandbox Code Playgroud)
这是因为卡车是汽车的子类,简单来说就意味着每辆卡车也是一辆汽车.但事情是,完成了类型检查,只从carList中选择了Trucks.
如果我们在Java中尝试相同的事情:
List<Car> carList = new ArrayList<Car>();
//add some objects to the collection
for(Truck t : carList)
//**PROBLEM**
Run Code Online (Sandbox Code Playgroud)
由于增强循环中的代码,代码甚至不会编译.相反,我们必须做这样的事情来获得相同的效果:
for(Car t : carList)
if(t instanceof Car)
//cast t to Truck and do truck stuff with it
Run Code Online (Sandbox Code Playgroud)
这与C#中没有任何问题的工作方式相同,但在Java中,您需要额外的代码.甚至语法几乎都一样!它有没有在Java中不起作用的原因?
但事情是,完成了类型检查,只从carList中选择了Trucks.
不,不是.如果您的列表包含除Trucks之外的任何内容,则C#中将发生运行时异常.基本上,在C#中,以下内容
foreach(Truck t in carList) {
...
}
Run Code Online (Sandbox Code Playgroud)
表现得像
foreach(object _t in carList) {
Truck t = (Truck)_t; // throws an InvalidCastException if _t is not a Truck
...
}
Run Code Online (Sandbox Code Playgroud)
另一方面,Java变体是类型安全的:您必须自己进行强制转换和类型检查.
那么,为什么Java和C#的行为不同?这是我的猜测:
C#foreach在具有泛型之前有关键字.因此,没有可能有一个List<Car>.如果C#选择了Java方式foreach,你必须写
foreach(object _c in myArraylistContainingOnlyCars) {
Car c = (Car)_c;
// do something with c
}
Run Code Online (Sandbox Code Playgroud)
这很烦人.另一方面,扩展的for循环和泛型在Java中引入了相同的版本(Java 5),因此不需要自动强制转换.
在C#中,当你写的时候
foreach(Truck t in carList)
Run Code Online (Sandbox Code Playgroud)
编译器理解的是(粗略地):
var enumerator = carList.GetEnumerator();
while (enumerator.MoveNext())
{
Truck t = (Truck)enumerator.Current;
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
如果carList包含非卡车车辆,则分配将在运行时失败.
您可以尝试以下控制台应用程序来说明:
namespace ConsoleApplication1
{
class Car
{
}
class Truck: Car
{
}
class Program
{
static void Main(string[] args)
{
Car[] cars = new[] { new Car(), new Truck() };
foreach (Truck t in cars)
{
Console.WriteLine("1 truck");
}
Console.Read();
}
}
}
Run Code Online (Sandbox Code Playgroud)
C#和java编译器在这里表现不同,因为在设计语言时已经做出了不同的选择.奇怪的是,"如果可能的话,尽快在编译时失败"是C#规范中的通用指南.这是一个没有应用它的情况,在我喜欢C#语言的地方,我更喜欢java行为.
但是,在C#中,linq提供了一种简单的方法来实现您认为具有的功能:
foreach (Truck t in carList.OfType<Truck>())
{
//do stuff
}
Run Code Online (Sandbox Code Playgroud)
这样,可以过滤掉可枚举的东西,只有卡车才能进入循环.
| 归档时间: |
|
| 查看次数: |
5863 次 |
| 最近记录: |