如何用Java封装数组

如何用Java封装数组,java,arrays,encapsulation,getter,Java,Arrays,Encapsulation,Getter,我从Java开始,学习setter、getter和封装。我有一个非常简单的程序,分为两类: Container有一个带有setter和getter的私有int数组(numArray) Main创建一个Container对象,并在totalArray方法中使用它 公共类容器{ private int numArray[]={0,0,0}; 公共int[]getNumArray(){ 返回努马拉; } 公共void setNumArray(int索引,int值){ Numaray[指数]=数值

我从Java开始,学习setter、getter和封装。我有一个非常简单的程序,分为两类:

  • Container
    有一个带有setter和getter的私有int数组(
    numArray

  • Main
    创建一个
    Container
    对象,并在
    totalArray
    方法中使用它


公共类容器{
private int numArray[]={0,0,0};
公共int[]getNumArray(){
返回努马拉;
}
公共void setNumArray(int索引,int值){
Numaray[指数]=数值;
}    
}
公共班机{
公共静态void main(字符串[]args){
容器内容=新容器();
System.out.println(totalArray(conte.getNumArray());
conte.getNumArray()[2]++;
System.out.println(totalArray(conte.getNumArray());
}
专用静态整数totalArray(整数v[]{
int-total=0;

对于(int conta=0;conta,您通常会查看您试图向类的调用者提供的接口

方法如下:

void addItem(Object item);
Object getItem(int index);
int getSize();
是您将在容器类中提供的类型。然后它们代表调用方与私有数组交互

如果希望返回整个数组而不允许更改,可以在getter中将数组复制到新数组中并返回副本


或者,如果使用Java集合类而不是基元数组,则它们会提供一个不可修改的xxx()方法(例如,
Collections.unmodifiableList(myList)
)它为集合提供了一个只读包装。

要防止人们更改数组,您所能做的就是在getter中提供它的副本

public int[] getArray() {
    return Arrays.copyOf(numArray, numArray.length);
}
通过这种方式,其他方法可以更改自己的数组副本,但是当它们再次调用getter时,它们会得到原始版本,没有更改。只有您提供的
setNumArray()
可以实际修改您的内部数组


否则,如果要完全阻止容器,则必须删除数组并使用不可变对象。库提供不可变列表,或使用。

如果要返回数组,请克隆它:

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

在公共API中,您应该确保向调用者清楚地记录这一点(实际上,无论哪种方式,如果调用者得到的数组是否会改变类的状态,他们都需要知道).

封装是隐藏实现的过程。集合是否将其数据存储在数组中是一个实现细节;如果它被封装,您将希望能够将其更改为其他存储类型

您正在公开状态(或派生状态)的事实本身因为getter和setter会破坏封装,并暗示您正在实现抽象数据类型,而不是真正的面向对象类。例如,
ArrayList
是一种数据类型,它不表示应用程序中任何真正的行为封装。这是否是您想要的,取决于该类型的使用方式和位置d


我倾向于使<代码>容器实现代码> >迭代-<代码>,如果它只是一个容器数据类型,或者提供一个内部迭代器方法,如果它是一个封装类,则传递一个访问者。如果它是抽象数据类型,则强烈地考虑使用内置的代码,如<代码> INT[]。

列表

还有另一种方法,它不复制阵列,但有其他缺点。我会将其用于非常大的阵列:

private A[] items;

public List<A> getItems() {
    return Collections.unmodifiableList(Arrays.asList(items));
}
private A[]项目;
公共列表getItems(){
返回集合.unmodifiableList(Arrays.asList(items));
}

我想建议一种不同于我在这里看到的所有答案的方法。在考虑封装时,也可以考虑“不要向对象请求数据,请对象为您操作其数据”的规则

您没有让我使用
numArray
,我将假设您的目标是从数学(而不是Java向量)创建一个数字“向量”,以用于示例目的

因此,您创建了一个包含一个双精度数组的NumericVector类。您的NumericVector将使用类似于
multiplyByScalar(双精度标量)
和addVector(NumericVector secondVector)的方法来添加元素

您的内部数组是完全封装的-它永远不会逃逸。对它所做的任何操作都是通过这些“业务方法”在NumericVector类中完成的。在对它进行操作后,您如何显示它?让NumericVector覆盖
NumericVector.toString()
,以便它正确打印出来,或者如果您有GUI,编写一个“控制器”类将数据从模型(NumbericVector)传输到视图(GUI)。这可能需要一种从NumbericVector流式传输元素的方法

这也表明了一些需要避免的事情:不要自动创建setter和getter,它们会破坏您的封装。您通常需要getter,但正如其他人所说的,您应该让getter返回数组的不可变版本。同时尽可能使类不可变。我前面提到的方法<代码>numericVector.addVector(numericVector secondVector)可能不应修改
numericVector
,而应随解决方案返回新的numericVector

这种方法(通常是OO)经常失败的情况是库——当你真的想给数组添加一点功能,但仍然把它作为一个通用数组。在这种情况下,Java通常根本不关心封装,它只是添加了一个可以为集合/数组做些事情的助手方法/类(请看“Arrays”对象(有很多很好的例子)

如何用Java封装数组

问题可能已经很清楚了,但是我想OOP的重点是将类设计为一个操作
private A[] items;

public List<A> getItems() {
    return Collections.unmodifiableList(Arrays.asList(items));
}
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;
    }    
}