我开始与Java和我的学习制定者吸气和封装。我有一个非常简单的程序,两类:

  • Container 有一个私人int阵列(numArray)与他的器&吸气。

  • Main 创建一个 Container 目,并使用它 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;
    }
}

问题:我可以改变私人int阵通过吸气,我知道那是因为 getNumArray 返回的一个参照 numArray, 不阵列本身。如果我们有兴趣在一个单元件阵列,我会做一个吸气指数值,但我想整个阵 totalArray 法。

我怎么可以阻止 numArray 被修改了他的课吗?

有帮助吗?

解决方案

所有你能做到防止人们改变你的阵列是提供一份它在吸气。

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

这种方式,其他方法可以改变自己的阵列,但是,当他们打电话的吸气再次,他们得到的原始版本,保持不变。只 setNumArray() 你可以提供实际修改内部阵列。

否则,如果你想完全的框容器,你必须放下阵列,使用一个不可改变的对象。 一些 图书馆提供不可改变的清单,或使用 集合。unmodifiableList.

其他提示

如果你想要返回的一个阵列,则将克隆:

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

在公共API你应该确保来文,明确的呼叫者(真的无论哪种方式,如果他们得到了一阵,这将改变国家的类别或没有-他们需要知道)。

通常你会看的接口,你想提供给你的呼叫者类。

方法,如:

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

是这样的事情,你将提供在你的容器类。然后,他们进行互动与私列在呼叫者的代表。

如果你希望返回的整体阵列,不允许改变你可以在吸气的复制的阵列入一个新的和返回的副本。

或者,如果使用Java收集的课程,而不是原始阵列,他们提供一个unmodifiableXXX()方法(例如 Collections.unmodifiableList(myList))提供一个只读包装的集合。

封装的过程中,隐藏的执行情况。是否收集储存数据的一个阵或不是一个执行情况的详细信息;如果这是封你会希望能够改变它的另一个储存的类型。

事实上,你都露出国家(或来源国)作为吸气,并制定者破坏了封装,并意味着你正在实施一个抽象的数据类型而不是一个真正面向对象的类。例如,一个 ArrayList 是一种数据类型而不代表任何真正的封装的行为,在应用程序。是否这就是你想要取决于如何和在那里的类型加以使用。

我会往往要么做 Container 实施 Iterable<Integer> 对于外部的互动如果这只是一个简单容器的数据类型,或者提供一个内部的迭代方法,向其通过一个访客,如果它旨在作为一个封类。如果它是一个抽象的数据类型,强烈考虑使用建立的诸如 int[]List<Integer> 代替。

还有另一种方式,这并不会使一个复制的阵列,但是有其它的缺点。我会使用它非常大阵列:

private A[] items;

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

如何封装一系列在Java

这个问题可能不够清楚,但是我猜这点 面向对象 是设计 一个类作为一个实体 操作这一系列并提取它自己的api。

如果你坚持下去然后返回 克隆阵列 / 防复制 是的路要走 为简单的情况.

我想提出一个不同的方法从所有的答案,我看到这里。它方便的时候你正考虑封装也认为规则"不要问的一个目的数据,要求的一个目操作在其数据对于你"。

你没给我使用 numArray, 我会假装你的目标是创建一个数字"矢量",从数学(不Java矢量)为例子的目的。

所以,你创建一个NumericVector类,包含一系列的两倍。你NumericVector会的方法一样 multiplyByScalar(double scalar) 和addVector(NumericVector secondVector)添加元素。

你的内部阵列是完全封它永远不会逃脱。任何操作上完成的,这样做是在你的NumericVector类通过这些"业务方法"。你怎么显示它后的工作吗?有NumericVector复盖 NumericVector.toString() 所以它打印出正确,或者如果你有一个GUI,写入"控制"类数据传输从模型(NumbericVector)你看(GUI)。这可能需要的一种方式流元素从你的NumericVector.

这还表明几件事情要避免:不要自动创建者以及吸气,他们打破你的封装。你经常需要吸气但是,正如其他人在这里已经说过,你应该让你吸气的回返的一个不可变的阵列。还尝试使你的课程不可改变的,无论可能的。这我早些时候提到的方法 numericVector.addVector(NumericVector secondVector) 可能不应修改 numericVector 但是,返回一个新的NumericVector的解决方案。

的情况下,这种(OO和一般)往往不是库-当你 真的 想添加一些功能要你的阵列,但仍把它留作为一般目的阵列。在这种情况下Java通常不会打扰封装在所有,只是增加了一个辅助方法/类可以做到的事情要的收集/array(看看"阵列"象对于一个伟大的例子)。

存储器有效的方式来做到这一点是...

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

此允许 ImmutableList 设定正确数目的项目的背阵的 List 并减少数量的中间物体的创建。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top