我可以在Java中调用构造函数中的方法吗?
我有一种情况,当类被实例化时,我只想读取一次配置文件。
假设我有一个名为 readConfig()
的方法,它读取配置并将其放入 Map
对象中。当程序需要使用配置值时,它会使用其定义键读取对象。我想知道构造函数仅在其生命周期中调用一次。我可以将我的方法 readConfig()
放入构造函数中,这将使我受益于一次调用,还是有另一种机制可以做到这一点?
I have situation, where I want to read configuration file only one time, when class is instantiated.
Suppose I have a method named readConfig()
, that reads configuration and puts it into a Map
object. When the program is required to use configuration value it reads object with it's define key. I want to know that constructor calls only once it's life cycle. Can I put my method readConfig()
into constructor, which would give me benefit of one time calling or is there another mechanism to do that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
你可以:这就是构造函数的用途。此外,您还要明确该对象永远不会在未知状态下构造(未加载配置)。
你不应该:在构造函数中调用实例方法是危险的,因为对象尚未完全初始化(这主要适用于可以重写的方法)。此外,构造函数中的复杂处理也会对可测试性产生负面影响。
You can: this is what constructors are for. Also you make it clear that the object is never constructed in an unknown state (without configuration loaded).
You shouldn't: calling instance method in constructor is dangerous because the object is not yet fully initialized (this applies mainly to methods than can be overridden). Also complex processing in constructor is known to have a negative impact on testability.
更好的设计是
Better design would be
在构造函数中调用不可重写的方法是一种可接受的方法。
如果该方法仅由构造函数使用,您可能想知道是否确实需要将其提取到方法(甚至
private
)中。如果您选择将构造函数完成的某些逻辑提取到方法中,则对于任何方法,您都必须选择适合方法要求的访问修饰符,但在这种特定情况下,它更重要的是保护方法免受重写该方法的执行必须冒着使超类构造函数不一致的风险。
因此,如果它仅由类的构造函数(和实例方法)使用,则它应该是
private
。否则,如果该方法在包内或子类中重用,则它应该同时是
package-private
和final
。使用这种方式没有任何好处或缺点。
我不鼓励在构造函数中执行太多逻辑,但在某些情况下,在构造函数中初始化多个事物可能是有意义的。
例如,复制构造函数可以执行很多事情。
多个 JDK 类说明了这一点。
以
HashMap
复制构造函数为例,它构造一个新的HashMap
,其映射与指定的Map
参数相同:提取映射填充的逻辑putMapEntries() 中的方法是一件好事,因为它允许:
clone()
和putAll()
也使用它Invoking a not overridable method in a constructor is an acceptable approach.
While if the method is only used by the constructor you may wonder if extracting it into a method (even
private
) is really required.If you choose to extract some logic done by the constructor into a method, as for any method you have to choose a access modifier that fits to the method requirement but in this specific case it matters further as protecting the method against the overriding of the method has to be done at risk of making the super class constructor inconsistent.
So it should be
private
if it is used only by the constructor(s) (and instance methods) of the class.Otherwise it should be both
package-private
andfinal
if the method is reused inside the package or in the subclasses.You don't have any benefit or drawback to use this way.
I don't encourage to perform much logic in constructors but in some cases it may make sense to init multiple things in a constructor.
For example the copy constructor may perform a lot of things.
Multiple JDK classes illustrate that.
Take for example the
HashMap
copy constructor that constructs a newHashMap
with the same mappings as the specifiedMap
parameter :Extracting the logic of the map populating in
putMapEntries()
is a good thing because it allows :clone()
andputAll()
use it too构造函数仅被调用一次,因此您可以安全地执行您想要的操作,但是从构造函数内部而不是直接调用方法的缺点是,如果方法失败,您将无法获得直接反馈。调用的方法越多,这就会变得越困难。
一种解决方案是提供方法,您可以在构造对象后调用这些方法来查询对象的“运行状况”。例如,方法
isConfigOK()
可用于查看配置读取操作是否正常。另一种解决方案是在失败时在构造函数中抛出异常,但这实际上取决于这些失败的“致命性”程度。
The constructor is called only once, so you can safely do what you want, however the disadvantage of calling methods from within the constructor, rather than directly, is that you don't get direct feedback if the method fails. This gets more difficult the more methods you call.
One solution is to provide methods that you can call to query the 'health' of the object once it's been constructed. For example the method
isConfigOK()
can be used to see if the config read operation was OK.Another solution is to throw exceptions in the constructor upon failure, but it really depends on how 'fatal' these failures are.
你可以。但是通过将其放在构造函数中,您会使对象难以测试。
相反,您应该:
init()
方法依赖注入框架为您提供这些选项。
第二个选项的示例(当对象由容器管理时最好使用):
当然,可以通过仅使用构造函数来编写,
但是这样您将无法提供模拟配置。
我知道第二个选项听起来更冗长并且容易出错(如果您忘记初始化)。如果您在构造函数中执行此操作,那么不会对您造成太大伤害。但是,使代码更加面向依赖注入通常是一个很好的做法。
第一个选项是最好的 - 它可以与 DI 框架和手动 DI 一起使用。
You can. But by placing this in the constructor you are making your object hard to test.
Instead you should:
init()
methodDependency injection frameworks give you these options.
An example of the 2nd option (best used when the object is managed by a container):
This, of course, can be written by just having the constructor
But then you won't be able to provide mock configurations.
I know the 2nd opttion sounds more verbose and prone to error (if you forget to initialize). And it won't really hurt you that much if you do it in a constructor. But making your code more dependency-injection oriented is generally a good practice.
The 1st option is best - it can be used with both DI framework and with manual DI.
单例模式
Singleton pattern
为什么不使用静态初始化块?其他详细信息请参见此处:
静态初始化块
Why not to use
Static Initialization Blocks
? Additional details here:Static Initialization Blocks