【问题标题】:(no) Properties in Java?(否)Java 中的属性?
【发布时间】:2026-02-24 23:55:01
【问题描述】:

所以,直到最近,我才任性地给自己保留了一个Java n00b,而我第一次真正的曝光带来了一个小小的震惊:Java 没有C# 风格的属性!

好吧,我可以忍受。但是,我也可以发誓,我在一个代码库中看到了 Java 中的属性 getter/setter 代码,但我不记得在哪里。那是如何实现的?有语言扩展吗?是不是和 NetBeans 有关系?

【问题讨论】:

    标签: java getter-setter


    【解决方案1】:

    Java 中有一个用于 getter 和 setter 的“标准”模式,称为 Bean properties。基本上任何以get 开头的方法,不带参数并返回一个值,都是一个属性获取器,用于命名为方法名称其余部分的属性(带有小写的起始字母)。同样,set 创建一个带有单个参数的 void 方法的 setter。

    例如:

    // Getter for "awesomeString"
    public String getAwesomeString() {
      return awesomeString;
    }
    
    // Setter for "awesomeString"
    public void setAwesomeString( String awesomeString ) {
      this.awesomeString = awesomeString;
    }
    

    如果您提出要求,大多数 Java IDE 都会为您生成这些方法(在 Eclipse 中,只需将光标移动到一个字段并点击 Ctrl-1,然后从列表中选择选项)。

    对于它的价值,为了可读性,您实际上也可以使用 ishas 代替 get 来获取布尔类型属性,如下所示:

    public boolean isAwesome();
    
    public boolean hasAwesomeStuff();
    

    【讨论】:

    • 我可以发誓我已经在一些 Java 代码中的某处看到过 C# 样式的属性语法,但是对于我的一生,我不记得在哪里以及如何使用。这确实不能回答我的问题,但我会因为令人敬畏的因素而接受它。也许我当时一直在产生幻觉。
    • 我很确定它不能在 Java 中完成,抱歉。有很多 JVM 语言确实对这类事情有一流的支持,但也许这就是你所看到的?
    • 如果您在成员变量前面加上 mm__ 之类的前缀,是否违反此约定,但是您没有在属性名称中包含该前缀?
    【解决方案2】:

    对我来说,问题有两个方面:

    1. 所有这些额外的方法 {get*/set*} 使类代码变得混乱。
    2. 无法将它们视为属性:
        public class Test {
          private String _testField;
    
          public String testProperty {
           get {
            return _testField;
           }
           set {
            _testField = value;
           }
          }
        }
    
        public class TestUser {
          private Test test;
    
          public TestUser() {
            test = new Test();
    
            test.testProperty = "Just something to store";
            System.out.printLn(test.testProperty);
          }
        }
    

    这是我想重新使用的那种简单的作业。不必使用“方法”调用语法。谁能提供一些关于 Java 发生了什么的答案?

    我认为问题还在于代码中不必要的混乱,而不是创建 setter/getter 的“困难”。我认为它们是丑陋的代码。我喜欢 C# 所拥有的。我不理解将这种功能添加到 Java 中的阻力。

    我目前的解决方案是在不需要保护时使用“公共”成员:

    public class IntReturn {
        public int val;
    }
    
    public class StringReturn {
        public String val;
    }
    

    这些将用于从 Lambda 中返回值:

    StringReturn sRtn = new StringReturn()
    
    if(add(2, 3, sRtn)){
        System.out.println("Value greater than zero");
    }
    
    public boolean add(final int a, final int b, final StringReturn sRtn){
        int rtn = a + b;
        sRtn.val = "" + rtn;
        return rtn > 0; // Just something to use the return for.
    }
    

    我也非常不喜欢使用方法调用来设置或获取类的内部值。

    如果您的信息以“不可变”的形式传输,那么新的 Java 记录 可能是一个解决方案。但是,它仍然使用 setter/getter 方法,只是没有 set/get 前缀。

    【讨论】:

      【解决方案3】:

      正如前面提到的 Eclipse,集成开发环境 (IDE) 通常可以自动创建访问器方法。

      您也可以使用 NetBeans 来完成。

      要为您的类创建访问器方法,请打开一个类文件,然后右键单击源代码编辑器中的任意位置并选择菜单命令重构、封装字段。 将打开一个对话框。单击全选,然后单击重构。 瞧,

      祝你好运,

      【讨论】:

        【解决方案4】:

        java 中没有 property 关键字(就像你可以在 C# 中找到它一样)拥有 1 个单词 getter/setter 的最接近的方法是像在 C++ 中一样:

        public class MyClass
        {
            private int aMyAttribute;
            public MyClass()
            {
                this.aMyAttribute = 0;
            }
            public void mMyAttribute(int pMyAttributeParameter)
            {
                this.aMyAttribute = pMyAttributeParameter;
            }
            public int mMyAttribute()
            {
                return this.aMyAttribute;
            }
        }
        //usage :
        int vIndex = 1;
        MyClass vClass = new MyClass();
        vClass.mMyAttribute(vIndex);
        vIndex = 0;
        vIndex = vClass.mMyAttribute();
        // vIndex == 1
        

        【讨论】:

          【解决方案5】:

          我很惊讶没有人提到project lombok

          是的,目前 java 中没有属性。还有一些其他缺失的功能。
          但幸运的是,我们有project lombok 正在努力改善这种情况。它每天也越来越受欢迎。

          所以,如果您使用的是 lombok:

          @Getter @Setter int awesomeInteger = 5;
          

          此代码还将生成getAwesomeIntegersetAwesomeInteger。所以和C# auto-implemented properties很像。

          您可以在here 获取有关 lombok getter 和 setter 的更多信息。
          你也应该看看other features。 我最喜欢的是:

          Lombok 与 IDE 完美集成,因此它将显示生成的方法,例如它们是否存在(建议、类内容、转到声明和重构)。
          lombok 的唯一问题是其他程序员可能不知道它。您始终可以delombok 代码,但这与其说是解决方案,不如说是一种解决方法。

          【讨论】:

          • 拥有在代码中看不到的方法似乎更糟。 c# 中的自动属性只是故事的一半——它主要是关于命名和分组相关的逻辑。
          • @JonnyLeeds 好吧,到底有多糟糕?您可以通过发现 @Getter@Setter 注释在代码中看到它们,它们也会显示在其他工具栏中(如大纲或建议)
          • 注解不会被继承——从而破坏了您进行面向对象开发的能力。如果您正在做 OO,那么您知道甚至没有理由拥有 getter 和 setter。公开行为比公开数据模型要好得多。我们远远超出了任何人都应该使用结构(bean)的地方。
          【解决方案6】:

          你可能不需要“get”和“set”前缀,为了让它看起来更像属性,你可以这样做:

          public class Person {
              private String firstName = "";
              private Integer age = 0;
          
              public String firstName() { return firstName; } // getter
              public void firstName(String val) { firstName = val; } // setter
          
              public Integer age() { return age; } // getter
              public void age(Integer val) { age = val; } //setter
          
              public static void main(String[] args) {
                  Person p = new Person();
          
                  //set
                  p.firstName("Lemuel");
                  p.age(40);
          
                  //get
                  System.out.println(String.format("I'm %s, %d yearsold",
                      p.firstName(),
                      p.age());
              }
          }
          

          【讨论】:

            【解决方案7】:

            来自Jeffrey Richter的CLR via C#:(我认为这些可能是JAVA中仍未添加属性的原因)

            • 属性方法可能会抛出异常;字段访问永远不会引发异常。
            • 属性不能作为outref 参数传递给方法;一个字段可以。
            • 属性方法可能需要很长时间才能执行;字段访问总是完成 立即地。使用属性的一个常见原因是执行线程同步, 它可以永远停止线程,因此,一个属性不应该是 如果需要线程同步,则使用它。在那种情况下,一种方法是优选的。 此外,如果您的类可以远程访问(例如,您的类派生自 System.MarshalByRefObject),调用属性方法会很慢,而且 因此,方法优于属性。在我看来,类派生自 MarshalByRefObject 绝不应该使用属性。
            • 如果连续调用多次,属性方法可能每次返回不同的值 时间;一个字段每次返回相同的值。 System.DateTime 类有一个只读的 Now 属性,返回当前日期和时间。每次查询这个 属性,它将返回不同的值。这是一个错误,微软希望 他们可以通过使 Now 成为方法而不是属性来修复类。 EnvironmentTickCount 属性是这个错误的另一个例子。
            • 属性方法可能会导致可观察到的副作用;字段访问永远不会。其他 换句话说,一个类型的用户应该能够设置一个类型定义的各种属性 他或她选择的任何顺序,而不会注意到类型中的任何不同行为。
            • 属性方法可能需要额外的内存或返回对某事物的引用 这实际上不是对象状态的一部分,因此修改返回的对象没有 对原始对象的影响;查询字段总是返回对对象的引用 这保证是原始对象状态的一部分。使用属性 返回副本可能会让开发人员感到非常困惑,而且这个特征经常 没有记录。

            【讨论】:

            • ""这是一个错误,Microsoft 希望他们可以通过将 Now 设为方法而不是属性来修复该类"" 是否有任何证据表明这一点?尝试用“getter and setter methods”替换所有单词“property”并再次阅读。文本应该仍然准确,这就是为什么我觉得这些论点很愚蠢。在我看来,这只是“我不了解属性是什么,因此我不喜欢它”......好吧,属性只是 getter 和 setter 方法的友好语法......所以如果你不喜欢属性,那么你也不应该喜欢 getter 和 setter...
            【解决方案8】:
            public class Animal {
            
                @Getter @Setter private String name;
                @Getter @Setter private String gender;
                @Getter @Setter private String species;
            }
            

            这有点像 C# 属性。我是http://projectlombok.org/

            【讨论】:

            • 注意:这将被视为语言扩展,并且往往会使 IDE 非常混乱。
            • @millimoose 你只需要一个 IDE 插件。可悲的是,每个使用此类代码的人都需要它。
            • “你需要一个 IDE 的插件”让我想卷起一份报纸,然后打给负责它的人。 (尽管可以说在 IDE 配置是代码库的主要构建系统的情况下更是如此。)
            【解决方案9】:

            为 Java 7 提出了“Java 属性支持”,但未将其纳入语言。

            如果有兴趣,请参阅http://tech.puredanger.com/java7#property 了解更多链接和信息。

            【讨论】:

              【解决方案10】:

              我只是发布 Java 5/6 注释和一个注释处理器来帮助解决这个问题。

              查看http://code.google.com/p/javadude/wiki/Annotations

              文档现在有点简单,但 quickref 应该可以理解这个想法。

              基本上,它使用 getter/setter(以及许多其他代码生成选项)生成一个超类。

              一个示例类可能看起来像

              @Bean(properties = {
                  @Property(name="name", bound=true),
                  @Property(name="age,type=int.class)
              })
              public class Person extends PersonGen {
              }
              

              有更多可用的示例,并且生成的代码中没有运行时依赖项。

              如果您试用并发现它有用,请给我发送电子邮件! -- 斯科特

              【讨论】:

                【解决方案11】:

                如果您需要,大多数 Java IDE 会自动为您生成 getter 和 setter 代码。有许多不同的约定,像 Eclipse 这样的 IDE 将允许您选择要使用的约定,甚至可以让您定义自己的约定。

                Eclipse 甚至包括自动重构,允许您将属性包装在 getter 和 setter 中,它会修改直接访问该属性的所有代码,以使其使用 getter 和/或 setter。

                当然,Eclipse 只能修改它知道的代码 - 您拥有的任何外部依赖项都可能被这种重构破坏。

                【讨论】:

                  【解决方案12】:

                  bean约定是这样写代码:

                  private int foo;
                  public int getFoo() {
                      return foo;
                  }
                  public void setFoo(int newFoo) {
                      foo = newFoo;
                  }
                  

                  在 JVM 上的其他一些语言中,例如 Groovy,您可以获得类似于 C# 的可覆盖属性,例如,

                  int foo
                  

                  通过简单的.foo 访问并利用默认的getFoosetFoo 实现,您可以根据需要覆盖它们。

                  【讨论】:

                    【解决方案13】:

                    如果您使用的是 eclipse,那么它可以自动为内部属性生成 getter 和 setter 方法,它可以是一个有用且省时的工具。

                    【讨论】:

                      【解决方案14】:

                      我的 Java 经验也不是很高,因此请随时纠正我。但是 AFAIK,一般惯例是这样编写两种方法:

                      public string getMyString() {
                          // return it here
                      }
                      
                      public void setMyString(string myString) {
                          // set it here
                      }
                      

                      【讨论】: