没有封装的类

时间:2014-07-16 03:41:03

标签: java encapsulation

我在理解Java中的封装方面遇到了一些麻烦。我所知道的是封装允许从程序中的任何其他地方隐藏信息(使用私有变量)。但是,有人能告诉我如何创建一个包含公共数据字段的类可能会导致问题?如果类提供了getter和setter方法,我不理解数据是如何被隐藏的。

   public class Student{

       private int id;
       private String name;
       private int grade;

  public Student(){
  }

  public Student(int id; String name, int grade){
      this.id = id;
      this.name = name;
      this.grade = grade;
  }

  public int getId(){
       return id;
  }

  public void setId(int id){
       this.id = id;
  }

  //more code

  }

3 个答案:

答案 0 :(得分:2)

“信息隐藏”一词并不一定要推断信息的安全性受到威胁。但要首先触及安全主题,在“完整代码”第2版中,Steve McConnell写道:

“公开成员数据违反了封装,并限制了对抽象的控制。”

这里的关键见解是,您无法控制使用您的代码的人与您希望代码的行为方式之间的交互。考虑到您的示例代码,请考虑这种情况:您的老板/客户/老师给出了一个要求/约束​​:对id字段进行一些错误检查,以确保它在一个范围内(可能只允许正数) 。你如何实现这个要求,以确保每当有人获得id后,它遵循该要求?

以下是该要求的示例实现:

public void setId(int id){
   if(id < 0) {
       this.id = 0;
   } else {
       this.id = id;
   }
}

此实现允许您确定在给定要求的情况下适当地设置了id字段,这允许您告诉使用代码的人员id始终是正数。不幸的是,当其他人使用您的代码时,他们可以直接引用成员变量并将其设置为如果它是公共的那样:

Student student = new Student();
student.id = -1;

当有人坐在IDE(甚至可能是你自己继续执行代码)时,他们怎么会知道不使用上面设置id字段的方法?控制对该字段的访问的最佳方法是只允许一个入口点。

也许“信息隐藏”最重要的方面是,如果您通过访问器和更改器控制对成员变量的访问,您可以在不让用户变得更聪明的情况下进行实现更改。请考虑以下情况:您的老板/客户/教师现在要求您将id字段加密为字母数字字符串,而不会影响已使用软件版本1的代码的用户。如果您允许直接访问成员变量,那么您无法更改id字段的内部表示,而不会破坏人们可能已经在您之上编写的代码。
他们可能是做这样的事情:

 Student student = new Student();
 int currentId = student.id;
 int idWithOffset = currentId + 100;

如果您突然需要/想要将id设为String或Id对象,会发生什么?如果您将id保持为私有,则可以根据需要进行这些更改,并在处理转换逻辑的setter / getter中编写代码,并且用户的代码永远不需要更改。

我最后(和个人最喜欢的理由)为什么'信息隐藏',例如让会员私密,有助于减少问题,是它删除了一些代码的细节,否则需要在UML图表,你的大脑,Javadocs中浮动等等......信息隐藏有助于抽象,这样你在工作这个课时就可以考虑课堂内的所有组件和玩家,而且在处理其他类时不必将它留在你的大脑中。

干杯。

另外,对于像Java语言这样的问题的一个很好的参考是Joshua Bloch(第2版)的“Effective Java”。

答案 1 :(得分:1)

这是一个公共字段可以使其类完全不可靠的示例。另一种私有版本可以保证其信息始终有效,并且不受欢迎的参与者无法接触。

公共字段类(不安全):

class VeryImportantCounterPublic  {
   public int currentCount;
   public VeryImportantCounterPublic(int initial_count)  {
      currentCount = initial_count;
   }
   public void incrementCount()  {
      currentCount++;
   }
   public int getCurrentCount()  {
      return  currentCount;
   }
}

私人字段类(安全):

class VeryImportantCounterPrivate  {
   private int currentCount;
   public VeryImportantCounterPrivate(int initial_count)  {
      currentCount = initial_count;
   }
   public void incrementCount()  {
      currentCount++;
   }
   public int getCurrentCount()  {
      return  currentCount;
   }
}

主:

public class CounterTest  {
   public static final void main(String[] ignored)  {
      VeryImportantCounterPublic counter = new VeryImportantCounterPublic(3);
      counter.incrementCount();
      counter.incrementCount();
      counter.incrementCount();

      //Should not be able to do this!!
      //But it's a public field, so you can  :(
      counter.currentCount = -203847382;

      System.out.println("[PUBLIC] Current count is " + counter.getCurrentCount());


      VeryImportantCounterPrivate counter2 = new VeryImportantCounterPrivate(3);
      counter2.incrementCount();
      counter2.incrementCount();
      counter2.incrementCount();

      //Can't do this. Compiler error:
      //counter2.currentCount = -203847382;

      System.out.println("[PRIVATE] Current count is " + counter2.getCurrentCount());
   }
}

输出:

[PUBLIC] Current count is -203847382
[PRIVATE] Current count is 6

完整来源:

public class CounterTest  {
   public static final void main(String[] ignored)  {
      VeryImportantCounterPublic counter = new VeryImportantCounterPublic(3);
      counter.incrementCount();
      counter.incrementCount();
      counter.incrementCount();
      counter.currentCount = -203847382;
      System.out.println("[PUBLIC] Current count is " + counter.getCurrentCount());


      VeryImportantCounterPrivate counter2 = new VeryImportantCounterPrivate(3);
      counter2.incrementCount();
      counter2.incrementCount();
      counter2.incrementCount();
      //Can't do this. Compiler error:
      //counter2.currentCount = -203847382;
      System.out.println("[PRIVATE] Current count is " + counter2.getCurrentCount());
   }
}


class VeryImportantCounterPublic  {
   public int currentCount;
   public VeryImportantCounterPublic(int initial_count)  {
      currentCount = initial_count;
   }
   public void incrementCount()  {
      currentCount++;
   }
   public int getCurrentCount()  {
      return  currentCount;
   }
}

class VeryImportantCounterPrivate  {
   private int currentCount;
   public VeryImportantCounterPrivate(int initial_count)  {
      currentCount = initial_count;
   }
   public void incrementCount()  {
      currentCount++;
   }
   public int getCurrentCount()  {
      return  currentCount;
   }
}

答案 2 :(得分:1)

Getters和Setters创建looser coupling

假设您聘请某人为您携带钱包。

如果此钱包的位置为public,则表明您的员工龋齿的位置。你可以直接抓住它,所以这个人必须随身携带它。

如果它的位置为private,则不再允许您携带钱包。你需要要求它(使用getter方法)。鉴于您的合同雇员仍然必须向您提供,他不必让您知道他保留的确切位置。所以他可以开始把它放在任何对他来说舒服的地方 - 在另一个口袋里或在他的包里 - 而不违反合同。因此,您仍然可以在需要时随身携带钱包,但您无需知道其携带的位置。