Can I call methods in constructor in Java?
在这种情况下,当类被实例化时,我只想读取一次配置文件。
假设我有一个名为
您可以:这就是构造函数的作用。此外,您还清楚地表明,永远不会在未知状态(未加载配置)下构造对象。
您不应该这样做:在构造函数中调用实例方法是危险的,因为该对象尚未完全初始化(这主要适用于可重写的方法)。此外,构造函数中的复杂处理也会对可测试性产生负面影响。
更好的设计是
1 2 3 | public static YourObject getMyObject(File configFile){ //process and create an object configure it and return it } |
- 工厂设计模式
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 ?
你用这种方法没有任何好处或缺点。我不鼓励在构造函数中执行太多的逻辑,但在某些情况下,在一个构造函数中初始化多个东西可能是有意义的。例如,复制构造函数可以执行很多操作。多个JDK类说明了这一点。以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public HashMap(Map<? extends K, ? extends V> m) { this.loadFactor = DEFAULT_LOAD_FACTOR; putMapEntries(m, false); } final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { int s = m.size(); if (s > 0) { if (table == null) { // pre-size float ft = ((float)s / loadFactor) + 1.0F; int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); } else if (s > threshold) resize(); for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { K key = e.getKey(); V value = e.getValue(); putVal(hash(key), key, value, false, evict); } } } |
提取
- 在其他上下文中重用该方法。例如,
clone() 和putAll() 也使用它 - (很小但很有趣)给出一个有意义的名字,用来传达执行的逻辑
构造函数只被调用一次,因此您可以安全地执行您想要的操作,但是从构造函数内部而不是直接调用方法的缺点是,如果方法失败,您不会得到直接反馈。你调用的方法越多,这就越困难。
一种解决方案是提供方法,您可以在构造对象后调用这些方法来查询其"运行状况"。例如,方法
另一种解决方案是在失败时在构造函数中抛出异常,但这实际上取决于这些失败有多"致命"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class MyClass() { private static MyClass instance = null; /** * Get instance of my class, Singleton **/ public static MyClass getInstance() { if(instance == null) { instance = new MyClass(); } return instance; } /** * Private constructor */ private MyClass() { //This will only be called once, by calling getInstanse() method. } } |
你可以。但是,通过将其放置在构造函数中,您将使对象难以测试。
相反,你应该:
- 为配置提供一个setter
- 有单独的
init() 方法
依赖注入框架为您提供了这些选项。
1 2 3 4 5 6 7 8 9 10 | public class ConfigurableObject { private Map<String, String> configuration; public ConfigurableObject() { } public void setConfiguration(..) { //...simply set the configuration } } |
第二个选项的示例(最好在对象由容器管理时使用):
1 2 3 4 5 6 7 8 9 10 11 |
当然,这可以通过只使用构造函数来编写。
1 2 3 |
但是,您将无法提供模拟配置。
我知道第二个选项听起来更冗长,而且容易出错(如果忘记初始化)。如果你在一个构造器中做的话,它不会真正伤害你那么多。但是,使代码更面向依赖注入通常是一个好的实践。
第一个选项是最好的-它可以与DI框架和手动DI一起使用。
为什么不使用