对于每个谈论对象处于"统一状态"这一事实的人,请参阅此问题的答案,该问题表明可以将对象参考传递,重新发给对象参考,从中调用方法,并在 之前访问了一个构造函数终止和所有字段已分配(包括包括 final
字段)。
所以这是用例:
public class Entity {
private final String name;
public Entity() {
this(toString()); //Nope, Chuck Testa
}
public Entity(String name) {
this.name = name;
}
}
编译器错误是:
在显式调用构造函数时无法参考实例方法。
请注意,toString()
尚未被过度,是Object
的默认调用。
我当然对此背后的哲学/技术原因感兴趣,因此,如果有人能解释一下,那将是一个很棒的奖励。但是,我正在寻找一种从该默认构造函数调用toString()
的方法,因为它指的是更具体的参数。实际用例更为复杂,最终将其归类为具有四个参数的构造函数,但这并不重要。
我知道我可以做这样的事情...
private static final String TO_STRING_CONSTRUCTOR_ARGUMENT = "aflhsdlkfjlkswf";
public Entity() {
this(TO_STRING_CONSTRUCTOR_ARGUMENT);
}
public Entity(String name) {
this.name = name == TO_STRING_CONSTRUCTOR_ARGUMENT ? toString() : name;
}
...但是这似乎是一个非常不高的解决方案。
那么,有什么办法将其拉开呢?或任何建议处理这种情况的最佳实践?
我希望在创建对象之前不要传递this
。相反,我会这样做:
public class Entity {
private final String name;
public Entity() {
this(null); // or whatever
}
public Entity(String name) {
this.name = name;
}
public String getName() {
return name != null ? name : Objects.hashCode(this);
}
}
如果您没有最终的name
生活,则可以使用一个初始化器块:
public class Entity {
private String name;
{name = this.toString();}
public Entity() {
}
public Entity(String name) {
this.name = name;
}
}
this
只有在完成this()
或super()
的所有呼叫之后才能使用。初始化器首先在构造仪致电super()
之后运行并允许访问this
。
关于这是编译器错误的原因,请参见JLS的第8.8.7节。这样做的原因尚不清楚,但考虑到new
'对象并在此处查看评估顺序时,构造链链必须是第一件事:
public Entity() {
this(toString());
}
在调用甚至超级构造函数之前,首先对tostring()进行评估。通常,这为非初始化状态打开了各种可能性。
作为个人喜好,我建议对象为创建有效状态所需的一切都应在其构造函数中可用。如果您无需调用对象层次结构中定义的其他方法而无法在默认构造函数中提供有效状态,请摆脱默认的构造函数,并将责任放在类的用户上,以向其他构造函数提供有效的字符串。
如果您最终只是尝试用ToString()的值调用另一个构造函数,那么我建议以下内容:
public Entity() {
name = toString();
}
实现了您设定实现并正确初始化名称的相同目标。
如JLS中所述,在初始化实例之前不允许使用。
但是,有一些方法可以一致地处理您的方案。
当我看到您的情况时,您要表示生成的值(ToString())或用户提供的值,该值可以为null。
鉴于此约束,使用TO_STRING_CONSTRUCTOR_ARGUMENT
至少在一个特定的用例中失败了,但是可能是模糊的。
本质上,您需要用类似于Google Guava中存在的可选替换字符串,并将包含在Java 8中,并以许多其他语言看到。
拥有一个字符串的语言/字符串持有人或您选择的任何内容,与此类似:
public class StringOptional {
private String value;
private boolean set = false;
public StringOptional() {}
public StringOptional(String value) {
this.value = value;
this.set = true;
}
public boolean isSet() { return set; }
public String getValue() { return value; }
}
然后,您可以将构造函数拨打,以了解推断路径。
public class Entity {
public Entity() {
this(New StringOptional());
}
public Entity(String s) {
this(new StringOptional(s));
}
private Entity(StringOptional optional) {
super(optional);
}
}
并将其存储为以下需求:
if (optional.isSet() ? optional.getValue() : toString();
这是我通常会处理可能无效的情况的方式,希望它可以作为答案。
您不能'使用'尚未创建的实例。通过调用第二个构造函数,您可以推迟创建,您无法在通话之前或致电行动中使用它。
您可以在类Entity
中使用静态方法工厂,然后将构造函数放在私有:
public class Entity {
private String name;
private Entity() {
}
public Entity(String name) {
this.name = name;
}
public static Entity createEntity() {
Entity result = new Entity();
result.name = result.toString();
return result;
}
}