当前位置: 首页 > 面试题库 >

如何在this(…)或super(…)之前“插入”代码?

屈健柏
2023-03-14
问题内容

在调用super(...)this(...)构造函数之前,有什么方法可以实现初步计算?考虑以下示例:

public class Test {
    private final int n;
    private final int m;
    private final int[] store;

    public Test(int n, int m) {
        /* This is common (most generic) constructor of the class Test.
         It is desirable to invoke it via this(...) call
         from any other constructor of this class
         since it contains some common initialization tasks,
         which are better to concentrate in one place instead
         of scattering them throught the class, due to
         maintainability and security reasons. */
        this.n = n;
        this.m = m;
        store = new int[n];
        // ...
    }

    public Test(Object data) {
        /* This is specific constructor. It depends on some parameters
         which must be processed prior to a call of the Test(int n, int m)
         constructor to get its arguments. The problem is, this processing
         cannot appear here because a call to this(...) must be the first
         statement in a constructor. */
        int a; // Must be calculated via lengthy code
        int b; // Must be calculated via lengthy code
        this(a, b); // <- Compiler error here
        // ... further initialization
    }
}

如何进行参数计算?最简单的解决方案是用静态方法替换特定的构造函数。但是如果它必须是 构造函数
而不是其他任何东西,该怎么办(例如,有可能在后代类中使用它)。到目前为止,我发现的最佳解决方案是引入一个静态内部类,该内部类包含公共构造函数的所有参数,并将其用于将参数存储在特定构造函数的开头:

public class Test {
    private final int n;
    private final int m;
    private final int[] store;

    protected static class ConstrParams {
        int nParam;
        int mParam;

        ConstrParams(int n, int m) {
            nParam = n;
            mParam = m;
        }
    }

    protected Test(ConstrParams params) {
        /* This is the common constructor now.
         It is marked as protected because it is essentially auxiliary,
         as well as the class ConstrParams is. */
        n = params.nParam;
        m = params.mParam;
        store = new int[n];
        // ...
    }

    public Test(int n, int m) {
        // This is public interface to the common constructor.
        this(new ConstrParams(n, m));
    }

    private static ConstrParams makeParams(Object data) {
        /* This is a procedure that inserts lengthy calculations
         before constructor chain invocation. */
        int a = 0; // Calculate a from data
        int b = 0; // Calculate b from data
        return new ConstrParams(a, b);
    }

    public Test(Object data) {
        // Specific constructor. Now compiles successfully.
        this(makeParams(data));
        // ... further initialization
    }
}

有更好的解决方法吗?当案件Test(Object data)必须调用一些super(...)构造函数,而不是this(...)因为我们得到在这种情况下缺乏灵活性,往往不能改变父类的代码更是雪上加霜。


问题答案:

这是我发现的一种通用方法。它允许在调用this(...)或之前插入任何代码super(...),从而克服Java的限制this(...)super(...)成为构造函数中的第一条语句。

public class Test {
    private final int n;
    private final int m;
    private final int[] store;

    public Test(int n, int m) {
        // Primary constructor is unchanged
        this.n = n;
        this.m = m;
        store = new int[n];
        // ...
    }

    private static class ConstrParams {
        private int nParam;
        private int mParam;
        /* This class can also be used by more than one constructor
         or independently, to calculate the parameters and store
         them for other purposes. */
        private ConstrParams(Object data) {
            /* Calculate the parameters and/or do any other operations
             (preprocessing) that you would do in the specific constructor prior
             to calling another constructor. You may even add as many auxiliary
             methods as needed into this class and use them in this constructor. */
            nParam = 1;
            mParam = 2;
        }
    }

    /* Intermediate constructor, the main purpose of which is to extract
     parameters (if any) from a ConstrParams object and pass them to a primary
     or an inherited constructor. If ConstrParams produces no parameters but
     makes some pre-this() or -super() actions, this constructor makes
     insertion of such actions available. */
    private Test(ConstrParams params) {
        this(params.nParam, params.mParam);
        /* You can also call super(...) instead of this(...).
         When calling super(...), primary constructor may even not exist. */
//        super(params.nParam, params.mParam);
        /* As the reference to ConstrParams vanishes upon return to the
         calling constructor, you may want to make some actions connected
         with the params object (post-processing) or store the reference to it
         into this object. If so, here's the right place to do it. Otherwise,
         no further action is generally needed in this constructor. */
    }

    public Test(Object data) {
        // Specific constructor. Now compiles successfully.
        this(new ConstrParams(data));
        // ... further initialization
    }
}

优势包括:

  • 调用构造函数的代码不受影响。这在使用时特别有用,super(...)因为对祖先类的更改通常是不希望的或不可能的。使用时this(...),上述方法不会影响任何依赖主构造函数的代码。
  • 它不取决于调用的构造函数所需的参数数量。只需在ConstrParams类的字段中添加任意数量的它们,然后在调用主构造函数或继承的构造函数之前进行提取。如果参数是联合计算的(即,将其计算分为两个或更多个独立的方法是不可能的,或者是很昂贵的),则这种方法可以做到这一点。在某些情况下(经常是)被调用的构造函数不带任何参数,而您只需要在this(...)super(...)调用之前在依赖的构造函数中执行一些操作(此类操作的一个示例是日志记录)。此解决方案使您可以执行此操作。
  • ConstrParams产生参数和/或产生副作用的辅助类可用于其他目的。如果主类的一个以上辅助构造函数需要克服this(...)/super(...)调用限制,则可以在其中引入更多构造函数。
  • 统一应用于this(...)super(...)调用。


 类似资料:
  • 我得到以下错误: 一个月后,我正在检查我的程序,之前相同的代码没有给出错误,我想我没有改变任何可能导致这一点的东西。我试图解决这个问题;所以在第1行的错误中提到:

  • 问题内容: 查看下面的示例代码 和 当我问到代码差异时,我并不是在说执行流程,这是显而易见的。 那么这些代码之间的 真正 区别是什么?建议何时 在 通话 前 使用您的代码,何时 在 通话 后 使用您的代码?我想在某些情况下这很重要。 问题答案: 您不应在之前放置任何代码,因为此方法可以使系统执行正确暂停应用程序所需的操作。您要在回调中执行的所有代码都应放在调用之后。希望这可以帮助。 活动报价: 注

  • 问题内容: 我觉得我看到了一种使用CSS content属性在元素之前插入换行标记的方法。显然这是行不通的: 但是你怎么做呢? 问题答案: 可以在伪元素生成的内容中使用 转义序列。。 您可能还需要添加到。 注意:表示一行的结尾。 ps另一种治疗方法是

  • 我正在使用这个版本的Eclipse:版本:2019-09 R(4.13.0)构建ID:20190917-1200 我想我已经设置了所有可能的设置 Eclipse 必须禁用所有导入之间的空白行,但是每当程序自动添加新导入时,它仍然会自动在导入组之间插入一个空行。 我所说的一个例子: 我设置了多个似乎会对此产生影响的设置,主要的一个似乎应该绝对控制它的设置是< br >窗口-

  • 问题内容: 关键字和之间有什么区别? 两者都用来访问类的构造函数吧?你们任何人都可以解释吗? 问题答案: 让我们考虑这种情况 输出将是 第三行正在打印“ animal:eat”,因为我们正在调用。如果我们调用,它将被打印为“ dog:eat”。

  • 问题内容: 我在下面有一个SQL插入程序,它工作正常,但是我希望它检查DATE = xxxx,NAME = xxxx和JOB = xxx并更新HOURS(如果它们存在),否则插入新行。SQL可以做到这一点吗? 尝试以下具有相同结果的OR替换,每次都会添加一个新行。 例如: 如果以下内容位于数据库中,并且John要更新其工作时间,它将检查名称,日期,作业是否与尝试插入的值相同,并且它们是否仅更新HO