抽象类正在使用它自己的抽象方法?
我正在查看游戏中的一些代码,发现了一些我以前从未见过的东西,我真的不知道发生了什么。
public abstract class Entity
{
public Entity(World world)
{
// irrelevent code
entityInit();
}
protected abstract void entityInit();
}
这是怎么回事?当它调用 entityInit()
时会发生什么?
I'm looking over some code in a game and I came across something that I haven't seen before and I don't really know whats going on.
public abstract class Entity
{
public Entity(World world)
{
// irrelevent code
entityInit();
}
protected abstract void entityInit();
}
What's going on here? What happens when it calls on entityInit()
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
抽象类永远不会被实例化。只有它的具体子类可以被实例化。因此,当调用具体子类(我们称之为
Foo
)构造函数时,它会调用super(world)
。然后,Entity 构造函数调用entityInit()
,该函数已被Foo
覆盖。因此它调用 FooentityInit
具体方法。请注意,这是不好的做法,因为将在尚未完全构造的对象上调用
entityInit
方法。因此,子类必须确保此方法不会访问它可能声明的任何字段,因为它们都将被统一初始化。An abstract class is never instantiated. Only its concrete subclasses can be instantiated. So, when the concrete subclass (let's call it
Foo
) constructor is called, it callssuper(world)
. The Entity constructor then callsentityInit()
, which has been overridden byFoo
. It thus calls the FooentityInit
concrete method.Note that this is bad practice, because the
entityInit
method will be called on a not yet fully constructed object. The subclass thus has to make sure this method doesn't access any field it might declare, because they will all be unititialized.所发生的情况是,
entityInit()
的具体子类实现被调用。由于Entity
是抽象的,因此只能从具体子类的构造函数调用它的构造函数,该子类的构造函数必须具有entityInit()
的实现。从抽象类的代码中调用抽象方法实际上是非常常见的,并且几乎是抽象方法的全部要点。另请参阅模板方法模式。
但是,从构造函数调用抽象方法(如本例所示)是有问题,应该避免,主要是因为抽象方法将在未完全初始化的对象上运行,因此可能处于不一致的状态。具体来说,
entityInit()
的实现将在定义它的类的构造函数之前运行。What happens is that the concrete subclass's implementation of
entityInit()
gets called. SinceEntity
is abstract, its constructor can only ever be called from a concrete subclass's constructor, which must have an implementation ofentityInit()
.Calling abstract methods from within code of the abstact class is actually perfectly common, and pretty much the entire point of abstract methods. See also the template method pattern.
However, calling abstract methods from a constructor as in this case is problematic and should be avoided, mainly because the abstract method will run on an object that is not completely initialized and thus possibly in an inconsistent state. Specifically, the implementation of
entityInit()
will run before the constructor of the class it's defined in.嗯,大多数情况下,这用于模板方法模式。
Entity
的子类非抽象类将实现entityInit()
方法。这些子类实现必须为该类定义它们的entityInit()
的方式。在维基百科中,它说......
在您的情况下,您不必担心子类必须
entityInit()
本身,因为构造函数默认会执行此操作:示例:
Well, mostly, this is used in Template Method pattern. The subclassed, non-abstract class of
Entity
will implement theentityInit()
method. These subclasses implement the way theirentityInit()
must be defined for that class.In Wikipedia, it says....
In your case, you won't worry about subclasses having to
entityInit()
itself, as the constructor will do this by default:Example:
好吧,没什么。
除非具体类实现抽象方法
entityInit
,否则您将无法创建使用该方法的Entity
类。Well, nothing.
Unless a concrete class implements the abstract method
entityInit
, you won't be able to create anEntity
class that will use the method.由于您需要创建一个具体的子类,因此您还需要实现
entityInit()
。然后将调用该方法。您不能创建抽象类的实例,而具体类(您可以创建其实例)不得具有抽象方法。所以一切都很好。
需要注意的是:请注意,如果访问子类中定义的字段,则在
entityInit()
中访问它们可能会导致 NullPointerException,因为它们可能未初始化。示例(基于您的班级):
虽然该示例没有多大逻辑意义,但它应该说明这一点。
首先将调用
Entity
构造函数,该构造函数又调用entityInit()
。但是,由于Person
的初始化块尚未运行,因此name
仍然为 null。Since you need to create a concrete subclass anyways you need to implement
entityInit()
as well. That method will then be called.You can't create instances of abstract classes and concrete class (which you can create instances of) must not have abstract methods. So everything is fine.
One note: be aware that if you access fields defined in the subclass, accessing them in
entityInit()
might result in a NullPointerException since they might not be initialized.Example (based on your class):
Although that example doesn't make much logical sense, it should illustrate the point.
First the
Entity
constructor will be called, which in turn callsentityInit()
. However, since the initializer block ofPerson
has not run yet,name
is still null.这是一种常见的做法。您在顶级方法中使用抽象方法,实现者只需要实现抽象,因此逻辑将留在基类中。
抱歉没有注意到它是一个构造函数......在那个位置很奇怪......
it's a common practice. You use the abstract method in a top level method, implementors will only need to implement the abstract, so logic will be left in base class.
Sorry haven't noticed it was a constructor... pretty strange in that position....
不要从构造函数中调用抽象/虚拟方法。它将调用具体的子类实现。但具体子类的成员变量还没有初始化。
另一种说法是不要让this从构造函数主体中逃逸。
但在这种特殊情况下,该方法的全部目的是初始化
this
对象的成员。所以没关系。但使用这种方法,我们必须链接超类的方法调用(如果它有实现)。Don't call abstract/virtual methods from the constructor. it would call the concrete subclass implementation. But the concrete subclass's member variables would have not initialized.
Another way to say that don't let your this escape from the constructor body.
But in this particular case, the whole purpose of the method is to initialize the members of the
this
object. So it's fine. but with this approach, we have to chain the method invocation of super class( if it has the implementation ).