Java 使用getter和setter具有私有属性的优势是什么?

Java 使用getter和setter具有私有属性的优势是什么?,java,c++,oop,Java,C++,Oop,在面向对象编程中,我曾经有过这个问题,现在仍然有: 如果我们 将为其创建一个公共getter和一个公共setter 在安全级别上,我看不到上述情况与将类成员声明为公共的情况之间有任何区别 谢谢 封装提供了数据隐藏和对成员变量的更多控制。如果一个属性是公共的,那么任何人都可以访问它,并且可以为它指定任何值。但是如果您的成员变量是私有的,并且您已经为它提供了一个setter。然后,您总是可以选择在setter方法中进行一些约束检查,以避免设置不合逻辑的值 例如,仅包含公共成员的类: class My

在面向对象编程中,我曾经有过这个问题,现在仍然有:

如果我们 将为其创建一个公共getter和一个公共setter

在安全级别上,我看不到上述情况与将类成员声明为公共的情况之间有任何区别


谢谢

封装提供了数据隐藏和对成员变量的更多控制。如果一个属性是公共的,那么任何人都可以访问它,并且可以为它指定任何值。但是如果您的成员变量是私有的,并且您已经为它提供了一个setter。然后,您总是可以选择在setter方法中进行一些约束检查,以避免设置不合逻辑的值

例如,仅包含公共成员的类:

class MyClass {
    public int age;
}

public MyClassUser {

    public static void main(String args[]) {
        MyClass obj = new MyClass();
        obj.age = -5 // not a logical value for age
    }
}
具有私有成员和setter的同一类:

 class MyClass {
     private int age;
     public void setAge(int age) {
         if(age < 0) {
            // do not use input value and use default
         } else { 
            this.age = age;
         }
     }
 }
class-MyClass{
私人互联网;
公共无效设置(整数){
如果(年龄<0){
//不要使用输入值,而使用默认值
}否则{
这个。年龄=年龄;
}
}
}

您可以稍后更改类成员的内部表示,将函数添加到GETER和SETER(例如通知观察者),而不改变接口(公共吸气剂和SETER)。

在封装的旁边,考虑SET不是简单设置值的情况。


如果你在很多课堂上使用它呢?现在你意识到你想改变它的功能了?您必须在手动设置的整个位置进行更改。然而,如果你有一个setter,生活会更轻松。

访问器方法为给定字段提供一个单点更新。这是有益的,因为验证逻辑或对字段的其他修改可以通过单个方法进行控制,而不是在整个代码库中直接访问字段

请参阅此IBM文档,其中详细介绍了更多好处:

在安全级别上,我看不到上述情况与将类成员声明为公共的情况之间有任何区别

眼前的问题是:

1) 如果要在设置值时检查某些条件,该怎么办

2) 如果子类希望通过ovveridng方法返回或设置其他内容,该怎么办


其他原因:

如果公共getter和公共setter只是返回私有属性的值并更改其值,那么我看不出有什么区别

但是,您正在实现封装,因此稍后您可以实现不同的行为,例如,包括setter或write-only/read-only属性的参数检查

class-Foo{
private int age=-1;//未设置值
公共设置(INTA){
if(a<0){
抛出新的IllegalArgumentException(“无效年龄”+a);
}
年龄=a;
}
公众假期(){
如果(年龄<0){
抛出新的InvalidStateException(“以前未设置年龄”)
}
回归年龄;
}    
}

简而言之:您获得了控制权,可以确保值是正确的。这叫做封装。

事实上,如果你在一个小项目上独自开发,你不会重用你的代码,这有点没用,但它基本上是一种好习惯

但是,在团队开发中,您可能需要对修改进行一些控制,您可以通过getter和setter来完成


此外,在某些类中,只有getter,因为setter将由构造函数或其他函数完成。

将变量声明为
private
在Java中称为
封装
在用Java或任何面向对象编程语言编写代码时,使用封装有以下几个优点:

  • 封装的代码更加灵活,易于根据新的需求进行更改
  • Java中的封装使单元测试变得容易
  • Java中的封装允许您控制谁可以访问什么
  • 封装还有助于用Java编写不可变类,这在多线程中是一个不错的选择 环境
  • 封装减少了模块之间的耦合,并增加了模块内部的内聚性,因为所有模块都是一件事 封装在一个地方
  • 封装允许您在不影响代码其他部分的情况下更改代码的一部分 另一个优势是

    在java中使变量私有,并为它们提供getter和setter,使您的类与JavaBean命名约定兼容


    如果您有一个范围有限的数据传输对象,并且按照设计,它应该没有与其关联的逻辑,那么我在getter和setter中看不到任何值


    但是,如果您有一个组件,该组件可能与逻辑相关,也可能与逻辑无关,或者可以广泛使用,那么隐藏数据存储方式的详细信息是有意义的。起初,看起来所有的getter和setter都很琐碎,只是填满了您的类,但随着时间的推移,您可能会向setter添加验证,甚至更改getter。e、 g.您可能会删除一个字段(并在将来返回一个常量)、将数据存储在委托对象中或从其他字段计算值。

    您的问题确实是字段和属性之间的区别。文件通常是私有的,属性会公开它们。贝娄引用了一个精彩的答案:

    属性公开字段。字段应该(几乎总是)保留 专用于类,并通过get和set属性访问。性质 提供一个抽象级别,允许您在 不影响外部事物访问它们的方式 利用你的课堂

    在C#中,自动属性将为您创建一个字段,而无需手动
    class Foo {
    
        private int age = -1;  // unset value
    
        public setAge(int a) {
            if (a < 0) {
                throw new IllegalArgumentException("Invalid age "+a);
            }
            age = a;
        }
    
        public getAge() {
           if (age < 0) {
               throw new InvalidStateException("Age was not previously set.")
           }
           return age;
        }    
    }
    
    public Prop { get; set; }
    public Prop { public get; private set; }
    public Prop { private get; public set; }
    // etc, you can specify access modifier as per your need
    
    class Person  //version 1.0
    {
      std::string name;
    
    public:
      std::string getName() const { return name; }
    
      void setName(const std::string &newName)
      {
        if (!newName.empty())  //disallow empty names
          name = newName;
      }
    };
    
    class Person  //version 1.1
    {
      std::string firstName;
      std::string lastName;
    
    public:
      std::string getFirstName() const { return firstName; }
    
      void setFirstName(const std::string &newFirstName)
      {
        firstName = newFirstName;
      }
    
      std::string getLastName() const { return lastName; }
    
      void setLastName(const std::string &newLastName)
      {
        if (!newLastName.empty())  //disallow empty last names
          firstName = newFirstName;
      }
    
      std::string getName() const
      {
        std::ostringstream s;
        if (!firstName.empty())
          s << fistName << ' ';
        s << lastName;
        return s.str();
      }
    
      void setName(const std::string &newName)
      {
        setFirstName(splitUntilLastSpace(newName));
        setLastName(splitFromLastSpace(newName));
      }
    };
    
    class Angle
    {
    public:
        void Set(MyAngleTypedef a_value) { m_angle = a_value; }
        // Note the 'Radians' type
        void SetRadians(Radians a_value) { m_angle = ConvertRadiansToOurUnit(a_value); }
        // Note the 'Degrees' type
        void SetDegrees(Degrees a_value) { m_angle = ConvertDegreesToOurUnit(a_value); }
    
        void Get(MyAngleTypedef a_value) const { return m_angle; }
        // Note the 'Radians' type
        Radians GetRadians(Radians a_value) const { return ConvertOurUnitToRadians(m_angle); }
        // Note the 'Degrees' type
        Degrees GetDegrees(Degrees a_value) const { return ConvertOurUnitToDegrees(m_angle); }
    private:
        // Raw value of the angle in some user-defined scale.
        MyAngleTypedef m_angle;
    }