Java封装概念不太清楚

时间:2015-11-04 09:58:34

标签: java oop

我对封装概念有点困惑。我在同一个问题上经历了不少答案,但仍然感到困惑。据我所知,封装是将实例变量设为私有,以便外部无法直接访问它。将提供公共getter和setter方法来访问私有变量 假设我们有一个类如下:

class Address
{
    int doorNumber;

    public int getDoorNumber()
    {
        //some code
    }

    public void setDoorNumber(int doorNumber)
    {
        //some code
    }
}

我们有另一个类,我们正在尝试访问Address类的变量。

class TestAddress
{

    public static void main()
    {
        Address add=new Address();
        add.doorNumber=10; //cannot be done
        add.setDoorNumber(10);
    }
}

虽然我们没有直接访问变量,但我们仍然使用setter方法修改doorNumber以将其值设置为10。基本上,外部世界仍然可以访问私有领域并以其想要的方式对其进行修改。我不明白封装的重点是什么。能否请您提供一些了解封装的例子。还有未使用封装的情况以及由此引起的问题。

3 个答案:

答案 0 :(得分:2)

请看下面的反例:

class Address
{
    int floor, door;

    public int getDoorNumber()
    {
        return floor*100+door;
    }

    public void setDoorNumber(int doorNumber)
    {
        int newFloor=doorNumber/100;
        if(newFloor<0 || newFloor>6)
            throw new IllegalArgumentException("no such door "+doorNumber);
        floor=newFloor;
        door=doorNumber-newFloor*100;
    }

}

调用setDoorNumber(10)的代码仍然有效,无需任何更改。属性“doorNumber”与对象内部表示的独立性,以及验证输入值的可能性,是封装的关键点。您不能使用public int doorNumber;

这样的字段来执行此操作

除此之外,还有开发人员认为像setDoorNumber(int)这样的方法与封装相矛盾,或者至少是封装的弱形式。更强的封装模型可以在没有这种public setter方法的情况下工作,但仅提供高级操作。这样的操作,比如预订酒店的房间,在内部将房间号码分配给地址之前,会执行更多相关操作,涉及其他对象,以及一致性检查......

答案 1 :(得分:1)

使用getter和setter比公开字段有一些好处:

  1. 您可以通过将int doorNumber;替换为可能不同类型的一个或多个字段来重新设​​计班级的内部。在这种情况下,您可以保留getter和setter,这意味着不必修改其他类。如果您有首选私有字段,则此类中的任何更改都会强制执行使用它的任何其他类的更改。

  2. 您可以在setter或getter中添加验证和/或重新格式化逻辑,而无需更改字段的类型。否则,如果您使用公共字段,则必须在访问此字段的任何其他类中重复此逻辑。

  3. 您可以在Effective Java第14项

    中阅读更多相关信息

答案 2 :(得分:1)

考虑这个例子:

public class Address {
   private int doorNumber;

   public int getDoorNumber() {
      return doorNumber;
   }

   public void setDoorNumber(int doorNumber) {
      if (doorNumber <= 0) {
          throw new IllegalArgumentException("door number must be > 0");
      }
      this.doorNumber = doorNumber;
   }
}

如果doorNumber字段被声明为public,则某些代码可能会违反地址中门号应为正数的约束。

考虑这个例子:

public class Address {
   private String doorNumber;

   public int getDoorNumber() {
      return Integer.parseInt(doorNumber);
   }

   public String getDoorNumber2() {
      return doorNumber;
   }

   public void setDoorNumber(int doorNumber) {
      this.doorNumber = doorNumber + "";
   }

   public void setDoorNumber(String doorNumber) {
      this.doorNumber = doorNumber;
   }
}

请注意,我们正在改进我们的API,以便我们可以代表地址"221B Baker St, London",但仍然允许使用我们旧的“门牌号是整数”API ...(某种程度上)。

但如果doorNumber已公开,那么我们就会被迫更改已使用Address.doorNumber的代码库中的每个位置。