今天我在一个巨大的项目中遇到了一个有趣的情况。 一个类有几个构造函数,它们用this()相互调用,最后会调用init(),build()等等。我想设置一个标志,然后调用this()和整个繁琐的过程,但调用this()应该是第一个。
如何在不修改Contructor标头并设置标志的情况下修改此类中的代码? :)
我知道这听起来像是hackish,也许这不是在学校学到的,这就是为什么至少对我来说有趣的原因。对于其他人来说在某些情况下也很有用。
这是一个基本的例子,我做了一些修改来模拟真正的问题,即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
}
}
我有一个简单的实现,但在我写这个问题之前我也得到了第二个。
我的重要问题没有答案,但我希望这会是,我可以接受某人的答案,谁想要建立声誉。
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 即使使用Class.forName(“java.awt.Rectangle”),某些IDE也足够智能地查找对此类的引用,如果您有源,但是如果它们在第三方库(插件)中,则可能不是。许可证检查例程想隐藏自己,开发人员有点经验将“Rectangle”拆分为“Rect”+“tagle”,甚至更复杂(decodeString)(但这已经足够了。非常怀疑你的超级智能编辑器可以找到参考文献:)
下一个解决方案可以是反射(这是我在这里输入的第二个解决方案,我在上面写过) - 没人提到
答案 0 :(得分:5)
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.
}
}
我也考虑重构其余部分。数百万行代码?哦,我的。
答案 1 :(得分:2)
今天我在一个巨大的项目中遇到了一个有趣的情况。一个类有几个构造函数,它们用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
答案 2 :(得分:2)
那么对this()
的调用必须是第一个,但是一个“hackish”方法来解决这个问题就是使用工厂设计模式并使用静态方法它应该看起来像这样:
public static Rectangle createRectangle(int width, int height) {
//do some some stuff
return new Rectangle(int x, int y, width, height)
}
答案 3 :(得分:1)
我会修改结构,以便每个构造函数都使用适当的参数调用init()
方法。然后,在init()
方法中,您可以执行当前4-arg构造函数中的操作。这允许构造函数设置标志等,而实际的初始化工作稍后发生,并且可以使标记符合。
答案 4 :(得分:1)
在这种情况下,我会选择一个带有额外参数的私有构造函数。
[...]
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();
}
[...]
作为一般规则,避免对构造函数做很多事情通常是好的。
答案 5 :(得分:0)
正如您链接的文档所示:
如果存在,则另一个构造函数的调用必须是构造函数中的第一行。
答案 6 :(得分:0)
将标志作为参数传递给构造函数,然后存储它。 (如果它用于确定用于创建实例的构造函数。) 我不明白你为什么不在主构造函数中首先调用你的神秘代码。