Frage

Ich fange mit Java und ich lerne über Setter, Getter und Verkapselung. Ich habe ein sehr einfaches Programm, zwei Klassen:

  • Container hat eine private int array (numArray) mit seinem Setter & Getter.

  • Main erstellt ein Container Objekt und verwendet es in totalArray Verfahren.


public class Container {
    private int numArray[]= {0,0,0};
    public int[] getNumArray() {
        return numArray;
    }
    public void setNumArray(int index, int value){
        numArray[index] = value;
    }    
}

public class Main {
    public static void main(String[] args) {
        Container conte = new Container();
        System.out.println(totalArray(conte.getNumArray()));
        conte.getNumArray()[2]++;
        System.out.println(totalArray(conte.getNumArray()));
    }
    private static int totalArray (int v[]){
        int total=0;
        for (int conta =0; conta<v.length;conta++){
            total+=v[conta];
        }
        return total;
    }
}

Problem: Ich kann die private int-Array durch den Getter ändern, ich weiß, das ist, weil getNumArray einen Verweis auf numArray zurückkommt, nicht das Array selbst. Wenn ich in einem einzigen Elemente des Arrays interessiert wäre, würde ich einen Getter mit einem Indexwert machen, aber ich möchte das gesamte Array für die totalArray Methode.

Wie kann ich verhindern, dass numArray aus aus seiner Klasse modifiziert werden?

War es hilfreich?

Lösung

Alles, was Sie tun können, Menschen zu verhindern, dass das Ändern Ihre Array ist eine Kopie davon in dem Getter zu liefern.

public int[] getArray() {
    return Arrays.copyOf(numArray, numArray.length);
}

Auf diese Weise können auch andere Verfahren können ihre eigene Kopie des Arrays ändern, aber wenn sie den Getter wieder anrufen, bekommen sie die ursprüngliche Version, unverändert. Nur die setNumArray() Sie tatsächlich ändern Sie Ihre interne Array zur Verfügung stellen kann.

Ansonsten, wenn Sie den Behälter vollständig zu blockieren, müssen Sie Arrays löschen und ein unveränderliches Objekt zu verwenden. Einige Bibliotheken bieten unveränderliche Listen oder a href verwenden <= "http: // java .sun.com / JavaSE / 6 / docs / api / java / util / Collections.html“rel = "noreferrer"> Collections.unmodifiableList .

Andere Tipps

Wenn Sie ein Array zurückgeben möchten, würden Sie es klonen:

  public int[] getArray() {
       return (int[]) numArray.clone();
  }

In einer öffentlichen API sollten Sie sicher sein, dass der Anrufer eindeutig zu dokumentieren (wirklich so oder so, wenn sie ein Array erhalten, die den Zustand der Klasse ändern wird oder nicht - sie müssen wissen).

Normalerweise würden Sie an der Schnittstelle sehen Sie die Anrufer Ihrer Klasse zu schaffen versuchen.

Methoden wie:

void addItem(Object item);
Object getItem(int index);
int getSize();

sind die Art von Dingen, die Sie in Ihrer Container-Klasse zur Verfügung stellen würden. Sie interagieren dann mit dem privaten Array im Namen des Anrufers an.

Wenn Sie das gesamte Array zurückzukehren, ohne Änderungen in dem Sie in den Getter kopieren Sie das Array in eine neue konnte und gibt die Kopie.

Alternativ, wenn Sie die Java-Collection-Klassen anstelle dem primitiven Arrays verwenden liefern sie eine unmodifiableXXX () -Methode (z Collections.unmodifiableList(myList)), die einen Nur-Lese-Wrapper bietet rund um die Sammlung.

Die Einkapselung ist der Prozess der Umsetzung zu verstecken. Ob die Sammlung speichert seine Daten in einem Array oder nicht, ist ein Implementierungsdetail; wenn es eingekapselt war würden Sie in der Lage sein, es zu einem anderen Speichertyp zu ändern.

Die Tatsache, dass Sie Zustand (oder abgeleiteten Zustand) als Getter und Setter bricht Verkapselung aussetzen und bedeuten, dass Sie einen abstrakten Datentyp, anstatt eine echte objektorientierte Klasse implementieren. Zum Beispiel ist ein ArrayList ein Datentyp, der in einer Anwendung keine echte Einkapselung von Verhalten darstellen. Ob das, was Sie wollen, hängt, wie und wo der Typ verwendet werden.

würde ich dazu neigen, entweder Container implementieren Iterable<Integer> für externe interation zu machen, wenn es einfach ein Container-Datentyp ist, oder bietet eine interne Iteratormethode, zu dem Sie einen Besucher passieren, wenn er als gekapselte Klasse bestimmt. Wenn es ein abstrakter Datentyp ist, sollten Sie stark stattdessen die integrierten in denen wie int[] oder List<Integer> verwendet wird.

Es gibt noch eine andere Art und Weise, die nicht über eine Kopie des Arrays machen, aber andere Nachteile. Ich würde es für sehr großen Arrays verwenden:

private A[] items;

public List<A> getItems() {
    return Collections.unmodifiableList(Arrays.asList(items));
}
  

Wie ein Array in Java verkapseln

Die Frage könnte klar genug sein, aber ich denke, der Punkt der OOP ist zu entwerfen eine Klasse als eine Einheit , die dieses Array manipuliert und extrahiert seine eigene api.

Wenn Sie bestehen dann ein zurückkehren Klon des array / defensive Kopie ist die Art und Weise zu gehen für einfache Fälle .

Ich möchte einen anderen Ansatz vorschlagen, aus allen Antworten, die ich hier gesehen habe. Es ist praktisch, wenn Sie der Verkapselung denken auch an die Regel denken „Seien Sie nicht ein Objekt für seine Daten fragen, fragen Sie ein Objekt auf seine Daten für Sie zu arbeiten“.

Du hast mir keine Verwendung für numArray, ich werde dein Ziel so zu tun, war ein numerisches „Vector“ von Mathematik (kein Java Vector) zum Beispiel Zwecke zu erstellen.

So haben Sie eine NumericVector Klasse, die ein Array von Doppel enthält. Ihr NumericVector würde Methoden wie multiplyByScalar(double scalar) und addVector (NumericVector secondVector) Elemente hinzuzufügen.

Ihre interne Array ist vollständig gekapselt - es nie entkommt. Jede Operation auf sie erfolgt in Ihrer NumericVector Klasse über diese „Geschäftsmethoden“ gemacht. Wie man es nach dem Betrieb auf sie angezeigt werden? Haben NumericVector Überschreibung NumericVector.toString() so ist es richtig druckt, oder wenn Sie eine GUI haben, schreiben Sie eine „Controller“ Klasse, um Daten von Ihrem Modell (NumbericVector) Ihrer Ansicht (GUI). Dies könnte eine Art und Weise erfordert Elemente aus dem NumericVector zu streamen.

Dies zeigt auch ein paar Dinge zu vermeiden: Verwenden Sie Getter und Setter nicht automatisch erstellen, sie Ihre Verkapselung brechen. Sie müssen oft Getter aber, wie andere hier schon gesagt haben, sollten Sie Ihre Getter zurückgeben eine unveränderliche Version des Arrays machen. Versuchen Sie auch auf Ihre Klassen unveränderlich, wo immer möglich zu machen. Diese Methode ich früher numericVector.addVector(NumericVector secondVector) erwähnt soll wohl nicht numericVector ändern, sondern eine neue NumericVector mit der Lösung zurück.

Der Fall, in dem dieser (und OO im Allgemeinen) oft nicht sind Bibliotheken - wenn Sie wirklich will eine wenig Funktionalität, um Ihre Array hinzufügen, aber verlassen sie noch als Allzweck-Array. In diesem Fall Java mit Kapselung der Regel nicht überhaupt die Mühe, es fügt nur eine Helfer-Methode / Klasse, die Dinge in die Sammlung / array tun kann (Blick auf dem „Arrays“ Objekt für ein paar tolle Beispiele).

Ein Speicher effizienter Weg, dies zu tun ist ...

package com.eric.stackoverflow.example;

import java.util.List;

import com.google.common.collect.ImmutableList;

public class Container {
    private int numArray[] = {0, 0, 0};
    public int[] getNumArray() {
        return ImmutableList.copyOf(numArray);
    }
    public void setNumArray(int index, int value) {
        numArray[index] = value;
    }    
}

Dies ermöglicht es der ImmutableList die richtige Anzahl von Elementen in der Trägeranordnung der List einzustellen und reduziert die Anzahl von Zwischenobjekten, die erstellt werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top