Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java封装的概念不是很清楚_Java_Oop - Fatal编程技术网

Java封装的概念不是很清楚

Java封装的概念不是很清楚,java,oop,Java,Oop,我对封装概念有点困惑。我在同一个问题上回答了不少问题,但仍然感到困惑。据我所知,封装是将实例变量作为私有变量,以便外部无法直接访问。将提供公共getter和setter方法来访问私有变量。 假设我们有一个如下所示的类: class Address { int doorNumber; public int getDoorNumber() { //some code } public void setDoorNumber(int doorN

我对封装概念有点困惑。我在同一个问题上回答了不少问题,但仍然感到困惑。据我所知,封装是将实例变量作为私有变量,以便外部无法直接访问。将提供公共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。基本上,外部世界仍然可以访问私有字段,并以它想要的方式对其进行修改。我不明白封装有什么意义。你能给我一些例子来理解封装吗。还包括未使用封装的场景以及由此可能出现的问题。

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

  • 您可以通过替换
    intdoornumber来重新设计类的内部结构。在这种情况下,可以保留getter和setter,这意味着不必修改其他类。如果您有首选的私有字段,则该类中的任何更改都将强制使用它的任何其他类中的更改

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


  • 您可以在有效的Java项目14中了解更多信息,使用getter和setter比公开字段有一些好处:

  • 您可以通过替换
    intdoornumber来重新设计类的内部结构。在这种情况下,可以保留getter和setter,这意味着不必修改其他类。如果您有首选的私有字段,则该类中的任何更改都将强制使用它的任何其他类中的更改

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

  • 您可以在有效的Java项目14中阅读更多关于它的信息,请考虑以下示例:

    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;
       }
    }
    
    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,以便能够表示地址,但仍然允许使用旧的“门牌号是整数”API。。。(有点)

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

    考虑以下示例:

    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;
       }
    }
    
    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,以便能够表示地址,但仍然允许使用旧的“门牌号是整数”API。。。(有点)


    但是如果
    doorNumber
    是公开的,那么我们将被迫更改代码库中使用
    Address.doorNumber
    的每个地方。

    看看下面的反例:

    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;
        }
    
    类地址
    {
    室内地板、门;
    public int getDoorNumber()
    {
    返回层*100+门;
    }
    公共无效设置门号(内部门号)
    {
    int NEWLOOR=门牌号/100;
    如果(新楼层6)
    抛出新的IllegalArgumentException(“无此类门”+门号);
    楼层=新楼层;
    门=门号新楼层*100;
    }
    
    }

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


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

    查看以下反例:

    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;
        }
    
    类地址
    {
    室内地板、门;
    public int getDoorNumber()
    {
    返回层*100+门;
    }
    公共无效设置门号(内部门号)
    {
    int NEWLOOR=门牌号/100;
    如果(新楼层6)
    抛出新的IllegalArgumentException(“无此类门”+门号);
    楼层=新楼层;
    门=门号新楼层*100;
    }
    
    }

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


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

    setDoorNumber
    有机会验证参数值并拒绝无效号码。进一步的