Pergunta

Estou começando com Java e estou aprendendo sobre setters, getters e encapsulamento. Eu tenho um programa muito simples, duas classes:

  • Container tem uma matriz int privado (numArray) com seu setter e getter.

  • Main cria um objeto Container e usa-lo no método totalArray.


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

Problema: eu posso mudar a matriz int privado através do getter, eu sei que é porque getNumArray retorna uma referência para numArray, não o próprio array. Se eu estivesse interessado em um único elemento da matriz, eu faria um getter com um valor de índice, mas quero que todo o conjunto para o método totalArray.

Como posso evitar numArray de ser modificado para fora de sua classe?

Foi útil?

Solução

Tudo o que você pode fazer para impedir as pessoas de mudar sua matriz é fornecer uma cópia do mesmo na getter.

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

Desta forma, outros métodos podem mudar a sua própria cópia da matriz, mas quando eles chamam o getter novamente, eles obter a versão original, inalterado. Apenas o setNumArray() você fornece pode realmente modificar a matriz interna.

Caso contrário, se você quiser bloquear completamente o recipiente, você tem que deixar cair matrizes e usar um objeto imutável. Algumas bibliotecas fornecer listas imutáveis, ou uso Collections.unmodifiableList .

Outras dicas

Se você quiser retornar um array, você cloná-lo:

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

Em uma API pública que você deve ter certeza de documento que claramente para os chamadores (realmente qualquer maneira, se eles estão recebendo uma matriz que vai mudar o estado da classe ou não - eles precisam saber).

Normalmente, você iria olhar para a interface que você está tentando fornecer aos chamadores de sua classe.

Métodos como:

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

são o tipo de coisas que você fornecer em sua classe recipiente. Eles, então, interagem com a matriz privada em nome do autor da chamada.

Se você quiser retornar a matriz inteira sem permitir mudanças que você poderia, no getter copiar a matriz em um novo e devolver a cópia.

Como alternativa, se você usar as classes de coleções Java em vez da matriz primitiva eles fornecem um método unmodifiableXXX () (por exemplo Collections.unmodifiableList(myList)) que fornecem um read-only invólucro em torno da coleção.

O encapsulamento é o processo de esconder a implementação. Se a recolha armazena os dados em uma matriz ou não é um detalhe de implementação; se ele foi encapsulado você gostaria de ser capaz de mudá-lo para outro tipo de armazenamento.

O próprio fato de que você está expondo estado (ou estado derivado) como getters e setters quebras de encapsulamento e implica que você está implementando um tipo de dados abstrato, em vez de uma verdadeira classe orientada a objeto. Por exemplo, um ArrayList é um tipo de dados que não representa qualquer verdadeira encapsulamento de comportamento numa aplicação. Se isto é o que você quer depende de como e onde o tipo é para ser usado.

Eu tenderia que quer fazer Container implementar Iterable<Integer> para interação externa se é simplesmente um tipo de dados recipiente, ou fornecer um método iterador interno para que você passe um visitante se destina como uma classe encapsulada. Se for um tipo de dados abstrato, considerar fortemente usando o built-in-ones, como int[] ou List<Integer> vez.

Existe ainda uma outra maneira, que não faz uma cópia da matriz, mas tem outras desvantagens. Eu usá-lo para matrizes muito grandes:

private A[] items;

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

Como para encapsular uma matriz em Java

A questão pode ser suficiente claro, no entanto eu acho que o ponto de OOP é a concepção de uma classe como uma entidade que manipula essa matriz e extratos a sua própria API.

Se você persistir em seguida, retornar a clone do array / cópia defensiva é o caminho a percorrer para casos simples .

Gostaria de sugerir uma abordagem diferente de todas as respostas que eu vi aqui. É útil quando você está pensando em encapsulamento também pensar da regra "não pergunte um objeto para seus dados, pedir um objeto para operar em seus dados para você".

Você não me deu um uso para numArray, eu vou fingir seu alvo era criar um formato numérico "Vector" da matemática (não um Vector Java) para fins de exemplo.

Assim você cria uma classe NumericVector que contém uma matriz de duplas. Seu NumericVector teria métodos como multiplyByScalar(double scalar) e addVector (NumericVector secondVector) para adicionar elementos.

Seu interno da matriz é totalmente encapsulado - nunca escapa. Qualquer operação feita sobre ele é feito em sua classe NumericVector via esses "métodos de negócio". Como você exibi-lo depois de operar sobre ele? Tem NumericVector override NumericVector.toString() por isso imprime corretamente, ou se você tiver um GUI, escrever uma classe "Controller" para transferir dados a partir do seu modelo (NumbericVector) para o seu ponto de vista (GUI). Isso pode exigir uma maneira de transmitir elementos de seu NumericVector.

Isso também indica algumas coisas a evitar: Não crie automaticamente setters e getters, eles quebram o encapsulamento. Muitas vezes você precisa getters, mas, como outros aqui já disseram, você deve fazer o seu getter retornar uma versão imutável da matriz. Além disso, tente fazer suas aulas imutável, sempre que possível. Esse método mencionei numericVector.addVector(NumericVector secondVector) mais cedo provavelmente não deve modificar numericVector mas retornar um novo NumericVector com a solução.

O caso em que esta (e OO em geral) muitas vezes não é bibliotecas - quando você realmente quiser adicionar um pouco de funcionalidade para sua matriz, mas ainda estão deixando-o como uma matriz de propósito geral. Neste caso Java não costuma se preocupar com encapsulamento em tudo, ele apenas acrescenta um método auxiliar / classe que pode fazer coisas para a coleção / array (olhar para o objeto "Arrays" para um monte de bons exemplos).

A memória maneira eficiente de fazer isso é ...

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

Isso permite que o ImmutableList para definir o número correcto de artigos na matriz de suporte do List e reduz o número de objectos intermédios que são criados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top