![](/img/trans.png)
[英]private members are not inherited. then how getters and setters able to access private fields in subClass?
[英]How to prevent direct access to private members outside of getters/setters in the same class?
給定一個 class 具有非平凡的 getter 和一些其他內部方法訪問相同的private
成員字段:
class TestType {
private String value;
public String getValue() {
return this.value == null || this.value.isEmpty() ? "default" : this.value;
}
public void setValue(String newValue) {
this.value = newValue;
}
public int getValueLength() {
return this.getValue().length();
}
}
我想禁止在getValueLength()
方法中繞過 getter。 getValueLength()
的以下實現應該會產生某種錯誤(單元測試失敗、checkstyle 錯誤或其他任何可以以通用方式自動化的錯誤):
public int getValueLength() {
// ERROR: possible NullPointerException
return this.value.length();
}
在我的實際代碼中,getter 內部進行了一些延遲加載,僅在第一次訪問時才加載實際值。 首先調用getValueLength()
可能會直接導致NullPointerException
或基於缺失值執行錯誤操作。
其動機是確保未來的開發人員不要忘記只使用 getter 方法而永遠不會直接訪問成員。 由於這是一個孤立的問題(即僅在專門添加這種延遲加載的情況下),如果需要一些額外的注釋是可以接受的,例如在成員本身上,它應該只在選定的方法中訪問,並且這些方法是標記為 - 或啟用/禁用特定規則的特定檢查樣式注釋。
只是把這個答案形成:
class LoadableVar<T> {
private T val;
private Supplier<T> loader;
public LoadableVar(Supplier<? extends T> loader) {
this.loader = loader;
}
public T get() {
if (this.val == null) {
//see: volatile and double-locking if multithreading
this.val = this.loader.get();
}
return this.val;
}
public void set(T overwrite) { //WARN: ignores the loader!
this.val = overwrite;
}
}
然后,將其應用於您的 class:
class TestType {
private final LoadableVar<String> value;
public TestType() {
//can also be passed into the class, or done however you desire
this.value = new LoadableVar<>(() -> /* load string from i/o, etc */);
}
public String getValue() {
return this.value.get();
}
public void setValue(String newValue) {
this.value.set(newValue); //I don't think this should be settable, personally
}
public int getValueLength() {
return this.getValue().length();
}
}
現在,當您在 TestType 的 scope 中編寫代碼時:
String s;
s = this.value; //compile error!
s = this.getValue(); //OK
s = this.value.get(); //OK
如您所見,以這種方式執行此操作還使TestType#getValue
變得多余,您可以簡單地允許value
成為protected
的成員(在這種情況下,我將刪除這些設置器並使其不可變)。
沒有辦法在代碼中強制執行此操作。
但是,由於您在評論中提到“希望有某種方法可以通過某種工具來實現它”,並且該問題被標記為checkstyle ,我相信您可以創建一個自定義規則:
<module name="Regexp">
<property name="id" value="valueField"/>
<property name="format" value="\bvalue\b"/>
<property name="illegalPattern" value="true"/>
<property name="ignoreComments" value="true"/>
<property name="message" value="Do not use 'value' field directly; use getValue() instead."/>
</module>
然后你會想要禁止檢查你自己的“有效”行:
<module name="SuppressWithNearbyCommentFilter">
<property name="idFormat" value="valueField"/>
</module>
在代碼中:
private String value; // SUPPRESS CHECKSTYLE
public String getValue() {
return this.value == null || this.value.isEmpty() ? "default" : this.value; // SUPPRESS CHECKSTYLE
}
public void setValue(String newValue) {
this.value = newValue; // SUPPRESS CHECKSTYLE
}
(還有其他方法可以通過注釋來抑制 Checkstyle 的檢查,您可能會發現它們在視覺上更令人愉悅。請參閱過濾器文檔。)
在實際運行 Checkstyle 時,您可能希望將其限制在那個源文件中。 例如,如果使用 Ant,您可以這樣做:
<taskdef resource="com/puppycrawl/tools/checkstyle/ant/checkstyle-ant-task.properties"
classpath="tools/checkstyle-8.33-all.jar"/>
<checkstyle config="checkstyle.xml">
<fileset dir="src/main/java" includes="**/TestType.java"/>
</checkstyle>
沒有辦法保護成員免受其自己的 class 的影響,但是您可以保護成員免受其子類/子類的影響。 例如:
class TestParent {
private String value;
public String getValue() {
return this.value == null || this.value.isEmpty() ? "default" : this.value;
}
public void setValue(String newValue) {
this.value = newValue;
}
}
class TestType extends TestParent {
public int getValueLength() {
return this.getValue().length();
}
}
這樣 TestType 仍然可以使用setValue()
和getValue()
,但是嘗試直接訪問this.value
將不起作用,因為value
在TestParent
中具有私有訪問權限
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.