3 Stimmen

Aufteilung einer Konstruktormethode in Teile - das Problem mit den Endwerten

Ich wollte den Konstruktor meiner Klasse in mehrere Teile aufteilen. Aber ich habe ein Problem...

Ist es möglich, einen endgültigen Wert in einer im Konstruktor aufgerufenen Methode zu initialisieren? Muss er direkt im Konstruktor initialisiert werden?

Das...

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();
    }
}

gibt mir ähnliche Fehler wie The final field A.L cannot be assigned .

Sie wird also wie ein Auftrag behandelt? ja?

Gibt es eine Möglichkeit der Aufteilung Konstruktor, um zu erreichen, was ich wollte?

Vielen Dank im Voraus.

3voto

Asaph Punkte 153684

Sie können dies nicht gemäß der Java-Sprachbeschreibung :

Eine leere finale Instanzvariable muss am Ende jedes Konstruktors (§8.8) der Klasse, in der sie deklariert ist, definitiv zugewiesen werden (§16.9); andernfalls tritt ein Kompilierfehler auf.

Sie können es im Konstruktor tun, weil der Compiler garantieren kann, dass der Konstruktor nur einmal pro Instanz aufgerufen wird. Der folgende Code lässt sich kompilieren. Ich habe ihn gerade überprüft:

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 */
    }
}

Sie können die endgültigen Variablen in Ihrer Nicht-Konstruktor-Methode nicht zuweisen, da nicht garantiert werden kann, dass sie nur einmal pro Instanz aufgerufen wird.

2voto

krock Punkte 27758

Final members können nur während der Initialisierung der Instanz gesetzt werden. Sie können also finale Felder bei der Deklaration, in einem Initialisierungsblock oder in einem Konstruktor initialisieren. Warum machen Sie nicht getFirstLine einen privaten Konstruktor:

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

2voto

Prince John Wesley Punkte 60530

Wie wäre es damit.

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()};
    }
}

2voto

Stephen C Punkte 665668

Ist es möglich, einen endgültigen Wert in einer im Konstruktor aufgerufenen Methode zu initialisieren?

Nein, das ist nicht möglich.

Muss es direkt im Konstruktor initialisiert werden?

Sie muss am Ende eines jeden Konstruktors initialisiert werden. Die Initialisierung kann in der Deklaration oder einem Instanzinitialisierer ... der als Teil aller Konstruktoren ausgeführt wird.

Sie wird also wie ein Auftrag behandelt? ja?

Ja!

Das Problem ist, dass die Methode podría zu einem beliebigen Zeitpunkt aufgerufen werden:

  • es könnte zweimal von einem Konstruktor aufgerufen werden,
  • kann nach der Konstruktion des Objekts aufgerufen werden, oder
  • könnte vor/nach der Zuweisung eine Ausnahme ausgelöst werden, so dass nicht klar ist, ob die Zuweisung erfolgt ist. (Und der Konstruktor könnte die Ausnahme abfangen ...)

Anstatt vom Compiler eine komplizierte Analyse zu verlangen, um sicherzustellen, dass die Zuweisung nur einmal und nur während der Konstruktion (und nicht danach) erfolgt, verbietet die JLS die Zuweisung in diesem Kontext einfach.

Gibt es eine Möglichkeit der Aufteilung Konstruktor, um zu erreichen, was ich wollte?

Sie können berechnen die Werte in einer separaten Methode, aber die eigentliche Initialisierung der final muss in den Konstruktoren, dem Deklarationsinitialisierer oder einem Initialisierungsblock durchgeführt werden.

(Gäbe es Unterklassen im Rahmen, könnten auch andere Tricks angewendet werden).

0voto

Maciej Ziarko Punkte 10564

OK, das habe ich getan, nachdem ich mich von den Antworten inspirieren ließ:

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);
    }
}

Ich habe eine private statische Klasse erstellt, die für das Lesen von Eingaben verantwortlich ist. Jetzt sollte sie logischer in separate Teile aufgeteilt werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X