在Java中它的惯例(据我所知)保持你的字段变量私有并使用getter和/或setter访问它们。这样您就可以设置更改变量值的规则。
但如果变量是最终的呢?例如:
public class Test {
public final int MY_INT;
public Test(int myInt) {
MY_INT = myInt;
}
}
这会被允许吗?它被编译并且工作正常,但是它被认为是好的代码吗?
答案 0 :(得分:16)
这可以编译,但它不被认为是好的代码。
MY_INT
违反了命名约定:带有全部大写字母的名称用于static final
变量,也称为"类常量" (另见this和this,Google's Java style guide)。要符合命名约定,最好重命名为myInt
。
建议您提供一个getter来隐藏类的实现细节。 接口只包含方法,而不包含字段。 如果您让其他类按名称引用此字段, 然后你就失去了以后更改名称或内部表示的自由。
但最重要的是, 子类不能覆盖字段,它们只能覆盖方法。 如果你提供一个getter而不是field, 子类将能够覆盖它并实现不同的行为。 因此,提供一个getter并禁止直接访问该字段本身会更好。
(感谢@Sotirios Delimanolis编码风格指南链接,非常感谢!)
答案 1 :(得分:5)
提供者答案不完整(即使是被选为“答案”的答案)。考虑如果相关字段是Collection或对象数组会发生什么。将所有字段设为私有并为这些字段提供“getter”是一种很好的做法。但更具体地说,你的getter应该返回一个(不可变的)对该字段的引用(即String
),或者是一个可变字段(即对象数组)的防御性副本。这是因为,即使您无法更改相关对象的基址,也可以通过简单地获取基址来更改对象(数组或集合)的内部。请记住,通过可变字段,我不仅仅是指数组或集合。它适用于任何可变类。
回到这个问题,吸气者是否需要?答案是不。 HOWEVER ,如果您想拥有强大的代码,那么遵循这些最佳做法符合您的最佳利益;即使只是为了养成良好的习惯。除非您经常练习,否则在编写代码时不会遵循良好的做法(而且很可能项目中的其他人也不会这样做)。
答案 2 :(得分:4)
如果客户端在为其分配了值之前可以访问您问题中的公共字段(即,不调用构造函数),则会出现明显的问题。具体而言,当客户端尝试访问它时,此字段无法具有预期/适当的值。尽管如此,正如评论中指出的那样,您尚未使用Test.MY_INT
标识符声明static
,这使得在不先调用构造函数的情况下检索此常量的值基本上是不可能的。
因此,做你正在做的事情似乎是明智的(就不变性而言)。但是,就好的代码而言,"你(正如其他人所说的那样)强迫你自己和你的客户通过名字明确地引用这个值。但是,如果您正在使用getter,并且需要更改MY_INT
的名称,同时保持常量的目的相同,那么您和您的客户端都不会被迫更改{{1}中的实现之外的任何内容}。
为了更明确,我为你的班级提供了一个getter和私有化的常量。
Test
我会像这样得到指定的整数值:
public class Test {
private final int MY_INT;
public Test(int myInt) {
MY_INT = myInt;
}
public int getAssignedIntValue() {
return MY_INT;
}
}
现在,假设我将Test test = new Test(1);
// with your class
test.MY_INT;
// with the above class
test.getAssignedIntValue();
重命名为MY_INT
以匹配命名约定。在这两种情况下,我都必须更改myInt
类中MY_INT
的所有出现次数。但是,当我需要使用新的常量名称获取值时,两个实现之间的区别变得清晰:
Test
注意:虽然这可能是一个可以接受的答案,但它并不一定具有最适用的推理。有关在更一般的背景下给出的推理,请参阅this answer。
答案 3 :(得分:3)
是的,你可以。只要您不在类级别或其他setter初始化该变量。
答案 4 :(得分:3)
我个人不喜欢公共字段,除非您的类只是一个数据类。你的课程是不可改变的,但你确定你永远不会想让它变得可变。如果有一天由于某种原因你需要一个可变副本,那么使用getter和setter更容易获得可变和不可变副本。
如果您有公共字段,客户将在其代码中使用您的字段,以后您将无法更改其名称。
你正在以这种方式打破封装。