在Java的构造函数中,如果要调用另一个构造函数(或超级构造函数),则它必须是该构造函数的第一行。我认为这是因为不允许您在其他构造函数运行之前修改任何实例变量。但是,为什么不能在构造函数委派之前使用语句,以便计算另一个函数的复杂值?我想不出任何正当的理由,在一些实际案例中,我编写了一些丑陋的代码来解决此限制。
所以我只是想知道:
关于我正在谈论的示例,请考虑我在答案中给出的一些代码。在该代码中,我有一个BigFraction类,该类具有BigInteger分子和BigInteger分母。“规范”构造函数是BigFraction(BigInteger numerator, BigIntegerdenominator)
表单。对于所有其他构造函数,我只是将输入参数转换为BigIntegers,然后调用“规范”构造函数,因为我不想重复所有工作。
在某些情况下,这很容易。例如,采用两个long
s 的构造函数是微不足道的:
public BigFraction(long numerator, long denominator)
{
this(BigInteger.valueOf(numerator), BigInteger.valueOf(denominator));
}
但是在其他情况下,则更加困难。考虑采用BigDecimal的构造函数:
public BigFraction(BigDecimal d)
{
this(d.scale() < 0 ? d.unscaledValue().multiply(BigInteger.TEN.pow(-d.scale())) : d.unscaledValue(),
d.scale() < 0 ? BigInteger.ONE : BigInteger.TEN.pow(d.scale()));
}
我觉得这很丑陋,但这可以帮助我避免重复代码。以下是我想做的事情,但是在Java中是非法的:
public BigFraction(BigDecimal d)
{
BigInteger numerator = null;
BigInteger denominator = null;
if(d.scale() < 0)
{
numerator = d.unscaledValue().multiply(BigInteger.TEN.pow(-d.scale()));
denominator = BigInteger.ONE;
}
else
{
numerator = d.unscaledValue();
denominator = BigInteger.TEN.pow(d.scale());
}
this(numerator, denominator);
}
更新资料
答案不错,但到目前为止,还没有提供我完全满意的答案,但我不太在意悬赏,所以我在回答自己的问题(主要是为了摆脱那个问题烦人的“您是否考虑过标记接受的答案”消息)。
建议的解决方法是:
BigInteger[]
或某种私有内部类,否则我无法返回多个值。反对此功能的主要观点是,在调用超构造函数之前,编译器将必须检查您是否未使用任何实例变量或方法,因为该对象将处于无效状态。我同意,但是我认为这比确保所有最终实例变量始终在每个构造函数中初始化的检查要容易得多,无论采用哪种路径通过代码。另一个论点是您根本无法预先执行代码,但这显然是错误的,因为用于计算超构造函数参数的代码正在
某处 执行,因此必须在字节码级别上允许它。
现在,我希望看到的是编译器不允许我接受此代码的一些 很好的 理由:
public MyClass(String s) {
this(Integer.parseInt(s));
}
public MyClass(int i) {
this.i = i;
}
然后像这样重写它(字节码基本上是相同的,我想):
public MyClass(String s) {
int tmp = Integer.parseInt(s);
this(tmp);
}
public MyClass(int i) {
this.i = i;
}
我看到的两个示例之间的唯一真正区别是,在第二个示例中tmp
调用后,“
”变量的范围允许对其进行访问this(tmp)
。因此,可能static{}
需要引入一种特殊的语法(类似于用于类初始化的块):
public MyClass(String s) {
//"init{}" is a hypothetical syntax where there is no access to instance
//variables/methods, and which must end with a call to another constructor
//(using either "this(...)" or "super(...)")
init {
int tmp = Integer.parseInt(s);
this(tmp);
}
}
public MyClass(int i) {
this.i = i;
}
我觉得这很丑陋,但这可以帮助我避免重复代码。以下是我想做的事情,但是在Java中是非法的…
您还可以通过使用返回新对象的静态工厂方法来解决此限制:
public static BigFraction valueOf(BigDecimal d)
{
// computate numerator and denominator from d
return new BigFraction(numerator, denominator);
}
或者,您可以通过调用私有静态方法为构造函数进行计算来作弊:
public BigFraction(BigDecimal d)
{
this(computeNumerator(d), computeDenominator(d));
}
private static BigInteger computeNumerator(BigDecimal d) { ... }
private static BigInteger computeDenominator(BigDecimal d) { ... }
问题内容: 在Jackson中,当您使用注释构造函数时,必须使用注释其参数。所以这个构造函数 变成这个: 我不明白为什么有必要。你能解释一下吗? 问题答案: Jackson必须知道以什么顺序将字段从JSON对象传递给构造函数。使用反射无法在Java中访问参数名称-这就是为什么您必须在注释中重复此信息的原因。
可能的重复: 为什么this()和super()必须是构造函数中的第一条语句? 为什么子类构造函数必须显式调用超类构造函数?这是什么原因呢?
我总是得到与此类似的结果。为什么第一个电话比其他电话要花10倍的时间?
问题内容: 以下代码向我返回错误信息: 我不明白。我的代码中的构造函数是第一条语句。我究竟做错了什么? 问题答案: 构造函数名称必须与类名称相同,因此请将类名称更改为或将构造函数名称更改为。 示例 (请注意,在Java中通常第一个字母是大写字母) :
或修饰符不允许与构造函数一起使用。为什么?我试过阅读标准文档,但没有很好地理解它。
在C++98中,如果你想让两个构造函数完成相似的事情,可以写两个大段代码相同的构造函数,或者是另外定义一个init()函数,让两个构造函数都调用这个init()函数。例如: class X { int a; // 实现一个初始化函数 validate(int x) { if (0<x && x<=max) a=x; else throw bad_X(x);