[英]java Constructor overload with this(), how to execute code before this()
今天,我在一個大型項目中遇到了一個有趣的情況。 一個類有幾個構造函數,它們使用this()相互調用,最后將調用init(),build()等。 我想設置一個標志,然后調用this()和整個繁瑣的過程,但是調用this()應該是第一個。
如何在此類內修改代碼,而無需修改Contructor標頭和設置標志? :)
我知道這聽起來像hackhack,也許這不是在學校學到的,這就是為什么至少對我來說有趣。 對於其他人,在某些情況下也可能有用。
這是一個基本示例,我做了一些修改以模擬實際問題init()方法。 http://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html
public class Rectangle {
private int x, y;
private int width, height;
private boolean flag;
public Rectangle() {
// execute code here, before this(), how? -set the flag true for eg.
this(0, 0, 0, 0);
}
public Rectangle(int width, int height) {
// execute code here to, something different as above, before this(), how?
this(0, 0, width, height);
}
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
init();
}
private void init(){
if(flag){
... do something new, else or different as the original, maybe return, even exit too
}
... do something... the old code
}
}
我有1個簡單的實現,但是在寫這個問題之前,我也有了第二個。
我的重要問題仍未得到解答,但我希望如此,並且我可以接受希望建立聲譽的某人的回答。
init()方法不能被編碼兩次,也不能在2個地方編寫代碼的邏輯,因為它不是一個好的編程范例,它可能會調用幾百萬行代碼。
-------------編輯已添加----------------
There is a way to known from which constructor was called: the full parametrized one or anything else with this() -I hope it gives more idea:
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
try {
throw new RuntimeException("Hacking use a lot of imagination");
} catch (Exception ex) {
StackTraceElement[] stackTraces = ex.getStackTrace();
// the first element is just above, no reason to check
String thisClassName = getClass().getName();
if (stackTraces[1].getClassName().equals(thisClassName)) {
if (stackTraces[1].getMethodName().equals("<init>")) {
flag = true;
}
}
}
init();
}
private void init() {
if (flag) {
System.out.println("\"... do something new, else or different as the original, maybe return, even exit too\"");
}
System.out.println("\"... do something... the old code");
}
-----------------------編輯添加解決方案1-非常簡單的情況
public Rectangle() {
// execute code here, before this(), how? -set the flag true for eg.
this(doVeryBanalHack(0, false), 0, 0, 0);
}
public Rectangle(int width, int height) {
// execute code here to, something different as above, before this(), how?
this(doVeryBanalHack(0, false), 0, width, height);
}
public Rectangle(int x, int y, int width, int height) {
this.x = doVeryBanalHack(x, true);
this.y = y;
this.width = width;
this.height = height;
// TODO deal with concurrency if you are in multithreaded environment, otherwise is done
this.flag = nextValueOfFlag;
init();
....}
private static boolean nextValueOfFlag;
private static int doVeryBanalHack(int retValue, boolean flagValue) {
System.out.println("\"execute code here, before this() it is too simple, it is banal static function\");
// TODO deal with concurrency if you are in multithreaded environment
nextValueOfFlag = flagValue;
}
在大型項目中無法更改功能簽名的原因是(其中之一)動態加載和反射用法:http: //tutorials.jenkov.com/java-reflection/constructors.html http:// tutorials .jenkov.com / java-reflection / dynamic-class-loading-reloading.html
http://www.java-forums.org/java-lang/7896-object-reflection-invoking-constructor-parameters.html某些IDE足夠聰明,即使使用Class.forName(“ java.awt .Rectangle”),如果您有資源,但如果它們在第三方庫(插件)中,則可能沒有。 許可證檢查例程想隱藏自己,並且開發人員有點經驗,因此會將“ Rectangle”拆分為“ Rect” +“ tagle”或什至更復雜(decodeString)(但這已經足夠了。高度懷疑您的超級智能編輯器是否可以查找引用比:)
下一個解決方案可以是反射(這是我在此處鍵入並在上面編寫的第二個解決方案)-尚未有人提及
一句話:您不能。 Java禁止在this
之前調用任何東西,因此不要理會這個想法。
可能會調用幾百萬行代碼。
這本身就是一個問題。 如果我是你,我會很擔心。
在我看來,這聽起來不像是構造函數,而更像是Builder模式。 也許您應該考慮構造函數的替代方法。
您需要一個構造器來設置標志,即使它是私有的。
public class Rectangle {
private int x, y;
private int width, height;
private boolean flag;
private Rectangle(int x, int y, int w, int h, boolean doInit) {
this.x = y;
this.y = y;
this.width = w;
this.height = h;
this.flag = doInit;
// Do what you must after this; adjust other ctors accordingly.
}
}
我也會考慮重構其余部分。 數百萬行代碼? 天啊。
今天,我在一個大型項目中遇到了一個有趣的情況。 一個類有幾個構造函數,它們使用this()相互調用,最后將調用init(),build()等。 我想設置一個標志,然后調用this()和整個繁瑣的過程,但是調用this()應該是第一個。
你不能 在我看來,該標志應該是傳遞給鏈式(可能是私有的)構造函數的參數之一:
public Rectangle() {
this(false, 0, 0, 0, 0);
}
public Rectangle(int width, int height) {
this(true, 0, 0, width, height);
}
private Rectangle(boolean flag, int x, int y, int width, int height) {
// Use everything including flag.
}
您可以在調用鏈式構造函數之前調用代碼,但是:
this
好,必須首先調用this()
,但是要解決此問題的一種“怪異”方法是使用工廠設計模式並使用靜態方法,它應該看起來像這樣:
public static Rectangle createRectangle(int width, int height) {
//do some some stuff
return new Rectangle(int x, int y, width, height)
}
我將修改結構,以便每個構造函數都使用適當的參數調用init()
方法。 然后,在init()
方法中,您可以執行4-arg構造函數中當前的操作。 這使構造函數可以設置標志等,而實際的初始化工作將在以后進行,並且可以使它們尊重標志。
在這種情況下,我會選擇一個帶有額外參數的私有構造函數。
[...]
public Rectangle() {
this(true, 0, 0, 0, 0);
}
public Rectangle(int width, int height) {
this(false, 0, 0, width, height);
}
public Rectangle(int x, int y, int width, int height) {
this(true, x, y, width, height);
}
private Rectangle(boolean flag, int x, int y, int width, int height) {
this.flag = flag;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
init();
}
[...]
通常,最好避免對構造函數做太多事情。
正如您鏈接到的文檔所說:
如果存在,則另一個構造函數的調用必須是該構造函數的第一行。
將標志作為參數傳遞給構造函數,並將其存儲。 (如果用來確定使用哪個構造函數創建實例的話。)我不明白為什么您不只是在主構造函數中首先調用神秘代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.