Разбиение метода конструктора на части - проблема с конечными значениями - PullRequest
3 голосов
/ 19 марта 2011

Я хотел разбить конструктор моего класса на части.Но у меня есть проблема ...

Можно ли инициализировать окончательное значение в методе, вызываемом внутри конструктора?Это должно быть инициализировано непосредственно в конструкторе?

Это ...

import java.util.Scanner;

public final class A
{
    private final int L;
    private final int D;
    private final int N;

    public A()
    {
        Scanner scanner = new Scanner(System.in);
        this.getFirstLine(scanner);

        /* the rest of the constructor method */
    }

    private void getFirstLine(Scanner scanner)
    {
        this.L = scanner.nextInt();
        this.D = scanner.nextInt();
        this.N = scanner.nextInt();
    }
}

дает мне ошибки, подобные The final field A.L cannot be assigned.

Так что это рассматривается как присвоение?Да?

Есть ли способ разделить конструктор, чтобы достичь того, чего я хотел?

Заранее спасибо.

Ответы [ 5 ]

3 голосов
/ 19 марта 2011

Вы не можете сделать это в соответствии с Спецификацией языка Java :

Пустая конечная переменная экземпляра должна быть определенно назначена (§16.9) в конце каждого конструктора (§8.8) класса, в котором она объявлена; в противном случае возникает ошибка времени компиляции.

Вы можете сделать это в конструкторе, потому что компилятор может гарантировать, что конструктор будет вызываться только один раз для каждого экземпляра. Код ниже компилируется. Я только что проверил это:

import java.util.Scanner;

public final class A
{
    private final int L;
    private final int D;
    private final int N;

    public A()
    {
        Scanner scanner = new Scanner(System.in);
        this.L = scanner.nextInt();
        this.D = scanner.nextInt();
        this.N = scanner.nextInt();

        /* the rest of the constructor method */
    }
}

Вы не можете назначить конечные переменные в вашем неконструкторном методе, потому что нельзя гарантировать, что он будет вызываться только один раз за экземпляр.

2 голосов
/ 19 марта 2011

Можно ли инициализировать окончательное значение в методе, который вызывается внутри конструктора?

Нет, это невозможно.

Это должно быть инициализировано прямо в конструкторе?

Он должен быть инициализирован в конце каждого конструктора. Инициализация может быть выполнена в объявлении или в инициализаторе экземпляра ..., который выполняется как часть всех конструкторов.

То есть это рассматривается как задание? Да?

Да!

Проблема в том, что метод можно вызывать в любой точке:

  • конструктор может вызвать его дважды,
  • он может быть вызван после того, как объект был построен, или
  • он может выдать исключение до / после назначения, оставляя неясным, произошло ли назначение. (И конструктор может поймать исключение ...)

Вместо того, чтобы требовать от компилятора сложного анализа, чтобы убедиться, что назначение происходит один и только один раз во время построения (а не после построения), JLS просто запрещает назначение в этом контексте.

Есть ли способ разбиения конструктора для достижения того, чего я хотел?

Вы можете вычислить значения в отдельном методе, но фактическая инициализация final должна быть выполнена в конструкторах, инициализаторе объявлений или блоке инициализатора.

(Если в кадре были подклассы, есть другие приемы, которые можно было бы использовать.)

2 голосов
/ 19 марта 2011

Как насчет этого?

import java.util.Scanner;

public final class A {

    private final int l;
    private final int d;
    private final int n;

    public A() {
        Scanner scanner = new Scanner(System.in);
        int[] list = this.getFirstLine(scanner);
        l = list[0];
        d = list[1];
        n = list[2];

        /* the rest of the constructor method */
    }

    private int[] getFirstLine(Scanner scanner) {
        return new int[]{scanner.nextInt(), scanner.nextInt(), scanner.nextInt()};
    }
}
2 голосов
/ 19 марта 2011

конечные элементы могут быть установлены только во время инициализации экземпляра.Таким образом, вы можете инициализировать конечные поля при их объявлении, в блоке инициализации или в конструкторе.Почему бы вам не сделать getFirstLine личным конструктором:

private A(Scanner scanner)
{
    this.L = scanner.nextInt();
    this.D = scanner.nextInt();
    this.N = scanner.nextInt();
}
0 голосов
/ 19 марта 2011

ОК, это то, что я сделал после того, как меня вдохновили ответы:

import java.util.Scanner;

public final class A
{
    private static final Scanner scanner = new Scanner(System.in);

    private static class FirstLine
    {
        public static int[] get()
        {
            return new int[]
            {
                A.scanner.nextInt(), 
                A.scanner.nextInt(), 
                A.scanner.nextInt()
            };
        }
    }

    private final int L;
    private final int D;
    private final int N;

    public A()
    {
        int[] valuesScanned = FirstLine.get();
        this.L = valuesScanned[0];
        this.D = valuesScanned[1];
        this.N = valuesScanned[2];
    }

    /*JUST TO TEST*/
    public static void main(String[] args)
    {
        A test = new A();
        System.out.println(test.L);
        System.out.println(test.D);
        System.out.println(test.N);
    }
}

Я создал закрытый статический класс, который отвечает за чтение ввода.Теперь оно должно быть более логично разделено на отдельные части.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...