是否完全违反Java方式来创建类似对象的结构?
class SomeData1 { public int x; public int y; }
我可以看到一个带有访问器和mutator的类更像Java.
class SomeData2 { int getX(); void setX(int x); int getY(); void setY(int y); private int x; private int y; }
第一个例子中的类是符号方便的.
// a function in a class public int f(SomeData1 d) { return (3 * d.x) / d.y; }
这不方便.
// a function in a class public int f(SomeData2 d) { return (3 * d.getX()) / d.getY(); }
小智.. 287
似乎许多Java人员不熟悉Sun Java编码指南,该指南认为当类本质上是"Struct"时使用公共实例变量是非常合适的,如果Java支持"struct"(当没有行为时).
人们倾向于认为getter和setter是Java方式,就像它们是Java的核心一样.事实并非如此.如果您遵循Sun Java编码指南,在适当的情况下使用公共实例变量,您实际上编写的代码比使用不必要的getter和setter使其混乱更好.
1999年的Java代码约定仍未改变.
10.1提供对实例和类变量的访问
没有充分理由,不要公开任何实例或类变量.通常,实例变量不需要显式设置或获取 - 通常是方法调用的副作用.
适当的公共实例变量的一个示例是类本质上是数据结构而没有行为的情况.换句话说,如果您使用结构而不是类(如果Java支持的结构),那么将类的实例变量公之于众是恰当的.
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
似乎许多Java人员不熟悉Sun Java编码指南,该指南认为当类本质上是"Struct"时使用公共实例变量是非常合适的,如果Java支持"struct"(当没有行为时).
人们倾向于认为getter和setter是Java方式,就像它们是Java的核心一样.事实并非如此.如果您遵循Sun Java编码指南,在适当的情况下使用公共实例变量,您实际上编写的代码比使用不必要的getter和setter使其混乱更好.
1999年的Java代码约定仍未改变.
10.1提供对实例和类变量的访问
没有充分理由,不要公开任何实例或类变量.通常,实例变量不需要显式设置或获取 - 通常是方法调用的副作用.
适当的公共实例变量的一个示例是类本质上是数据结构而没有行为的情况.换句话说,如果您使用结构而不是类(如果Java支持的结构),那么将类的实例变量公之于众是恰当的.
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
真的使用常识.如果你有类似的东西:
public class ScreenCoord2D{ public int x; public int y; }
然后将它们包裹在吸气剂和制定者中是没有意义的.你永远不会以任何其他方式在整个像素中存储x,y坐标.吸气剂和制定者只会减慢你的速度.
另一方面,有:
public class BankAccount{ public int balance; }
您可能希望在将来的某个时间点更改计算余额的方式.这应该真的使用getter和setter.
最好知道你为什么要运用良好的练习,以便你知道什么时候可以改变规则.
这是一个经常讨论的话题.在对象中创建公共字段的缺点是您无法控制设置它的值.在有许多程序员使用相同代码的小组项目中,避免副作用很重要.此外,有时最好返回字段对象的副本或以某种方式对其进行转换等.您可以在测试中模拟此类方法.如果您创建新类,则可能看不到所有可能的操作.这就像防御性编程 - 有一天getter和setter可能会有所帮助,创建/使用它们并不需要花费太多.所以它们有时很有用.
在实践中,大多数领域都有简单的getter和setter.可能的解决方案如下所示:
public property String foo; a->Foo = b->Foo;
更新:在Java 7中或者可能永远不会添加属性支持.其他JVM语言(如Groovy,Scala等)现在支持此功能. - 亚历克斯米勒
为解决可变性问题,您可以将x和y声明为final.例如:
class Data { public final int x; public final int y; public Data( int x, int y){ this.x = x; this.y = y; } }
调用尝试写入这些字段的代码将得到编译时错误"字段x被声明为final;无法分配".
然后,客户端代码可以具有您在帖子中描述的"简写"便利
public class DataTest { public DataTest() { Data data1 = new Data(1, 5); Data data2 = new Data(2, 4); System.out.println(f(data1)); System.out.println(f(data2)); } public int f(Data d) { return (3 * d.x) / d.y; } public static void main(String[] args) { DataTest dataTest = new DataTest(); } }
public
字段public
当您真的想要包装类的内部行为时,请不要使用字段.以java.io.BufferedReader
为例.它有以下字段:
private boolean skipLF = false; // If the next character is a line feed, skip it
skipLF
在所有读取方法中读取和写入.如果在一个单独的线程中运行的外部类恶意修改skipLF
了读取中间的状态怎么办?BufferedReader
肯定会变得混乱.
public
字段以这Point
堂课为例:
class Point { private double x; private double y; public Point(double x, double y) { this.x = x; this.y = y; } public double getX() { return this.x; } public double getY() { return this.y; } public void setX(double x) { this.x = x; } public void setY(double y) { this.y = y; } }
这将使计算两点之间的距离非常痛苦.
Point a = new Point(5.0, 4.0); Point b = new Point(4.0, 9.0); double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));
除了普通的getter和setter之外,该类没有任何行为.当类只表示一个数据结构时,使用公共字段是可以接受的,并且没有,并且永远不会有行为(瘦的getter和setter 在这里不被认为是行为).它可以这样写得更好:
class Point { public double x; public double y; public Point(double x, double y) { this.x = x; this.y = y; } } Point a = new Point(5.0, 4.0); Point b = new Point(4.0, 9.0); double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
清洁!
但要记住:不仅你的班级必须缺乏行为,而且也应该没有理由在将来也有行为.
(这正是这个答案所描述的.引用"Java编程语言的代码约定:10.编程实践":
适当的公共实例变量的一个示例是类本质上是数据结构而没有行为的情况.换句话说,如果你会使用
struct
,而不是一个类(如果支持Javastruct
),那么它的合适使类的实例变量公开.
所以官方文档也接受这种做法.)
此外,如果您更确定上述Point
类的成员应该是不可变的,那么您可以添加final
关键字来强制执行它:
public final double x; public final double y;
顺便提一下,您作为示例提供的结构已经存在于Java基类库中java.awt.Point
.它有x和y作为公共字段,请自行检查.
如果您知道自己在做什么,并且团队中的其他人知道这一点,那么公共领域是可以的.但是,你不应该依赖于它,因为它们能引起头痛作为使用对象涉及到开发商的错误,好像他们是堆栈分配结构(Java对象总是发送到方法作为参考而不是复印件).
回复:aku,izb,John Topley ......
注意可变性问题......
省略getter/setter似乎是明智的.在某些情况下,它实际上可能没问题.这里显示的提议模式的真正问题是可变性.
问题是,一旦您传递包含非最终公共字段的对象引用.该引用的任何其他内容都可以自由修改这些字段.您无法再控制该对象的状态.(想想如果字符串是可变的会发生什么.)
当该对象是另一个对象的内部状态的重要部分时,它会变坏,您刚刚暴露了内部实现.为防止这种情况,必须返回对象的副本.这可行,但可能会造成大量的一次性副本创建的GC压力.
如果您有公共字段,请考虑将该类设置为只读.将字段作为参数添加到构造函数,并将字段标记为final.否则,请确保您没有暴露内部状态,如果需要为返回值构造新实例,请确保不会过度调用它.
请参阅:Joshua Bloch撰写的" 有效Java " - 第13项:偏好不变性.
PS:还要记住,如果可能的话,现在所有的JVM都会优化掉getMethod,导致只有一个字段读取指令.
我已经在一些项目中尝试了这个,理论上getter和setter在语义上毫无意义地混淆了代码,并且其他语言似乎可以很好地使用基于约定的数据隐藏或职责划分(例如python).
正如其他人在上面提到的那样,你遇到了两个问题,而且它们并不是真正可以修复的:
几乎所有Java世界中的自动化工具都依赖于getter/setter约定.正如其他人所指出的那样,jsp标签,弹簧配置,eclipse工具等也是如此...反对你的工具期望看到的东西是长期会话的一个秘诀,通过谷歌试图找到非标准的启动方式春豆.真的不值得麻烦.
一旦你有一个包含数百个公共变量的优雅编码应用程序,你可能会发现至少有一种情况,它们是不够的 - 你绝对需要不变性,或者你需要在变量设置时触发一些事件,或者你想抛出变量更改的异常,因为它将对象状态设置为令人不快的事物.然后,你会遇到令人尴尬的选择,在任何变量被直接引用的地方,用一些特殊的方法来混乱代码,在应用程序的1000个变量中有3个具有特殊的访问形式.
这是完全在一个独立的私人项目中工作的最佳情况.一旦将整个事物导出到可公开访问的库中,这些问题就会变得更大.
Java非常冗长,这是一件很诱人的事情.不要这样做.