[英]Which is preferable in Java: storing a field twice, or storing it as protected in the base class?
我很少使用繼承,但是當我這樣做時,有時會遇到以下問題。 鑒於:
Logger
。 我已經看到以兩種不同的方式解決了這個問題:
class ChildClass extends ParentClass {
private Logger logger;
public ChildClass(Logger logger) {
super(logger);
this.logger = logger;
}
}
class ParentClass {
private Logger logger;
public ParentClass(Logger logger) {
this.logger = logger;
}
}
要么:
class ChildClass extends ParentClasss {
public ChildClass(Logger logger) {
super(logger);
}
}
class ParentClass {
protected Logger logger;
public ParentClass(Logger logger) {
this.logger = logger;
}
}
我猜另一個選擇是ParentClass
的受保護的getter,但是我從未遇到過。
就我個人而言,我更傾向於第二種方法,其理由是較小的數據大小勝過封裝,但是我經常在野外遇到第一種版本。 有沒有更可取的方式來做到這一點?
我認為沒有絕對優選的方法,但是總的來說,如果您知道記錄器可能是子類所需要的(就像在這種情況下一樣),則應該通過保護字段或添加一個字段來使其可訪問。受保護的吸氣劑。 有人會說添加吸氣劑是可取的。
您看到“野外”重復字段的原因之一是因為子類是第二個編寫的,修改父類並非總是可能的。
從設計和性能的角度來看,第二個選項更好,假設在父類中需要記錄器。 具有兩個包含相同值的屬性可能會造成混淆,並占用更多空間。 (僅當創建大量實例時,后者才有意義。)
然而:
private
,並提供一個protected final
getter方法。 protected
屬性,則還應該將其定為final
。 如果使用的是標准日志記錄API之一,則通常的做法是讓對象實例化其自己的記錄器; 例如與Log4j
this.logger = Logger.getLogger(this.getClass());
這些都是相對較小的問題,但是(IIRC)默認PMD規則集包含有關protected
屬性的規則。
...但是我經常在野外遇到第一個版本。
是的,很多原始代碼並不完美,而且我認為這些是相對較小的問題。
跟進
說兩個字段都是最終的。 在第一種情況下,您是否認為編譯器會足夠聰明,以找出指針始終是相同的並將它們折疊到同一字段中?
不。我認為編譯器不會這樣做:
任何優化都必須面對屬性的反射訪問(甚至更新)。 在這種情況下,反射代碼將需要了解優化,並將字段的一個版本的請求映射到另一個。
在大多數情況下,這種優化的收益很小,而JIT編譯器弄清楚該優化是有效的,其CPU成本將是巨大的。
(請記住,此優化只能由JIT編譯器執行。字節碼編譯器沒有足夠的信息來進行優化。具體地說,它不知道類構造函數的最終代碼是什么。請注意,除非存在大量有關對象的實例,否則節省的空間將是微不足道的。)
但是,我使用Guice已有一段時間了,這似乎是注入記錄器而不是依賴靜態工廠的一種標准做法。
我認為這是Guice特有的習慣用法。 普通的Java應用程序/庫在我的經驗中很少將記錄器作為參數。
我還將使用第二種方法。
我不確定您為什么如此關注內存占用,但是兩種方法之間的區別可以忽略不計。 從技術上講,您不會兩次存儲 logger
。 在Java中,所有對象變量都是指針 。 因此,在第一種情況下, ParentClass
和ChildClass
都指向同一logger
實例。
第二種方法是具有繼承優勢(共享功能和屬性)的經典示例。
老實說,這是一個完全由您決定的設計決策,對內存占用量都沒有真正的重大影響,但是第二種方法比第一種方法更多地利用了OOP原理。
如果您絕對不想將字段公開給外界,則需要將其設置為private
,因為即使protected
字段也對其包的成員(以及任何子類)可見。 但是,在Logger
的情況下,這可能會過大。 繼承可能更易於理解/維護實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.