2014-09-19 282 views
0

我在回顾我的面向对象,并对对象有一些疑问。那么我有一个超类Ship这也是一个抽象类。船有一些子类,即Submarine,Destroyer等。为抽象类创建对象

我知道我不能创建Ship类的对象,因为它是抽象的。但为什么以下仍然有效?

Ship s1 = new Submarine("ship 1"); 
+1

只是因为你不能实例化一个抽象类,并不意味着你不能拥有这种类型的对象。你也可以拥有某个接口的对象,比如'List strings = new ArrayList <>();' – Davio 2014-09-19 13:10:42

+2

因为在这一行你创建了一个'Submarine'类型的对象,然后将它转换为'Ship'类型。 '潜艇'是一艘'船' – SimY4 2014-09-19 13:11:12

+2

阅读这一个:http://stackoverflow.com/questions/4321386/create-object-of-abstract-class-and-interface – 2014-09-19 13:11:47

回答

1

简单来说,抽象类意味着你不能创建这个类的新实例。
但是,它仍然可以声明对象为Ship编译时类型 VS 运行时类型)使用多态性,允许你做一些有趣的东西,像Ship数组,它包含两个SubmarineDestroyer(还有更多)。

Ship[] army = new Ship[2]; 
army[0] = new Submarine("0"); 
army[1] = new Destroyer("1"); 

for(Ship s : army) { 
    s.fire(); 
} 

在此示例中,我们可以在两个对象调用fire()因为fire()Ship的方法。由于船只的攻击取决于船只的类型(潜艇不会像驱逐舰一样发射),因此您将fire()方法设为Ship摘要并在SubmarineDestroyer中实施。

这些技巧在OOP中是必不可少的,并且允许您实现强大的设计模式。如果你是一个初学者,着眼于strategy patterntemplate method pattern,他们几年前改变了我的OOP的愿景;)

希望这个小样本可以帮助你:)

2

行:Ship s1 = new Submarine("ship 1");

没有创建抽象类Ship,其仅仅是一个参考,它指向对象儿童类Submarine的对象。你正在做的是创建子类的对象。

1

这是由于多态性。

父类的引用可以容纳子类对象。但是使用此引用可以调用在子类中被正确覆盖的方法。

1

您应该区分运行时类型和编译时类型。

比方说,你有下面的语句:

Ship s1 = new Submarine("ship 1"); 
  • 编译时类型的s1是分配statment,例如的左手侧类型编译时的类型是Ship。您可以将s1分配给继承Ship的任何类型。

  • 运行时类型s1是赋值语句的右侧,例如, s1的运行时间类型是具体执行Ship(在你的情况 - Submarine)。

更多信息:

+0

+1以突出显示编译时类型和运行时类型之间的区别:) – NiziL 2014-09-19 13:21:09

0

只是因为你不能实例化一个抽象类,并不意味着你不能有一个类型的对象。您也可以拥有某个界面的对象,如List<String> strings = new ArrayList<>()

您声明了一个抽象方法,因为默认实现没有意义。

考虑一个名为shape的类,其子类circlesquare。 A shape有一个面积,但circle的面积计算与square的面积不同。

您可以在抽象类shape创建一个名为getArea抽象方法,让circlesquare提供其执行情况。

0

s1是一艘船,您可以使用抽象类中定义的所有方法,但只能使用这些方法。 如果您的Submarine类中有其他方法(例如:dive,periscopeUp,...),则不能调用它们,因为它们未在抽象Ship类中定义。

使用此功能主要适用于集合,例如,您现在可以在列表中存储不同类型的Ship。

List<Ship> ships = new ArrayList<Ship>(); 
ships.add(new Submarine("sub 1")); 
ships.add(new Destroyer("des 1")); 

如果您需要定义一个“List<Submarine> subs”你只能存储潜艇在该列表中的类。