Java中的类结构对象
创建类似结构的对象是否完全违背了Java的方式Java中的类结构对象,java,oop,struct,Java,Oop,Struct,创建类似结构的对象是否完全违背了Java的方式 class SomeData1 { public int x; public int y; } 我可以看到一个类,它的访问器和变异器更像Java class SomeData2 { int getX(); void setX(int x); int getY(); void setY(int y); private int x; private int y; } 第一个示例中的
class SomeData1 {
public int x;
public int y;
}
我可以看到一个类,它的访问器和变异器更像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();
}
这不太方便
// 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();
}
如果你知道它永远是一个简单的结构,你永远不会想给它附加行为,我看不出有什么害处。如果Java方式是OO方式,那么是的,创建一个带有公共字段的类打破了信息隐藏的原则,即对象应该管理自己的内部状态。(因此,我不仅仅是在对您说行话,信息隐藏的一个好处是,类的内部工作隐藏在接口后面——如果您想更改结构类保存其中一个字段的机制,您可能需要返回并更改使用该类的任何类…) 您也不能利用对JavaBean命名兼容类的支持,如果您决定(比如)在使用表达式语言编写的JavaServer页面中使用该类,则会受到影响 JavaWorld这篇文章也可能会让您感兴趣,您可以考虑什么时候不实现accessor和mutator方法
如果您正在编写一个小型解决方案,并且希望尽量减少所涉及的代码量,那么Java方式可能不是正确的方式-我想它总是取决于您和您试图解决的问题。这是一个经常讨论的话题。在对象中创建公共字段的缺点是您无法控制设置给它的值。在许多程序员使用相同代码的小组项目中,避免副作用很重要。此外,有时最好返回字段对象的副本或以某种方式对其进行转换等。您可以在测试中模拟此类方法。如果创建一个新类,可能看不到所有可能的操作。这就像防御性编程——总有一天,getter和setter可能会有所帮助,而且创建/使用它们不会花费很多成本。所以它们有时是有用的 实际上,大多数字段都有简单的getter和setter。可能的解决方案如下所示:
public property String foo;
a->Foo = b->Foo;
更新:在Java7中添加属性支持的可能性很小,也许永远不会。其他JVM语言,如Groovy、Scala等,现在确实支持此功能。-Alex Miller这是一个关于面向对象设计的问题,而不是Java语言。通常,在类中隐藏数据类型并仅公开作为类API一部分的方法是一种很好的做法。如果公开内部数据类型,以后就永远无法更改它们。如果隐藏它们,您对用户的唯一义务就是方法的返回和参数类型。顺便说一句,您作为示例给出的结构已经存在于Java基类库中,名为
Java.awt.Point
。它将x和y作为公共字段
如果您知道自己在做什么,并且团队中的其他人也知道,那么可以使用公共字段。但是你不应该依赖它,因为它们会引起麻烦,就像开发者在使用对象时使用堆栈分配的结构一样(java对象总是作为引用而不是副本发送给方法)。真正使用常识。如果您有以下情况:
public class ScreenCoord2D{
public int x;
public int y;
}
那就没有什么意义了,把他们用接球手和二传手包起来。你永远不会以任何其他方式以整像素存储x,y坐标。能手和二传手只会让你慢下来
另一方面,由于:
public class BankAccount{
public int balance;
}
您可能希望在将来某个时候更改余额的计算方式。这应该真正使用getter和setter
最好知道你为什么要应用好的实践,这样你就知道什么时候可以改变规则。re:aku、izb、John Topley 注意易变性问题 省略getter/setter似乎是明智的。在某些情况下,它实际上可能是好的。此处所示的拟议模式的真正问题是可变性 问题是,一旦您传递了一个包含非最终公共字段的对象引用。任何其他引用都可以自由修改这些字段。您不再可以控制该对象的状态。(想想如果字符串是可变的会发生什么。) 当该对象是另一个对象的内部状态的重要部分时,情况就会变得糟糕,因为您刚刚公开了内部实现。为了防止这种情况,必须返回对象的副本。这是可行的,但创建的大量一次性拷贝可能会造成巨大的GC压力
如果您有公共字段,请考虑将类设为只读。将字段作为参数添加到构造函数中,并将字段标记为final。否则,请确保不公开内部状态,并且如果需要为返回值构造新实例,请确保不会过度调用它
参见:Joshua Bloch的《第13项:支持不变性》PS:还请记住,现在所有JVM都会尽可能优化getMethod,只产生一条字段读取指令 为了解决易变性问题,您可以将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;
}
}
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;
}
}
试图写入这些字段的调用代码将得到编译时错误“字段x已声明为最终;无法分配”
然后,客户端代码就可以像您在文章中描述的那样方便快捷
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();
}
}
使用公共字段访问的问题与使用new而不是factory方法的问题是一样的——如果您以后改变主意,所有现有的调用者都会被破坏。因此,从API发展的角度来看,咬紧牙关使用getter/setter通常是个好主意 另一方面,当您强烈控制对类的访问时,例如在用作内部数据结构的内部静态类中。在这种情况下,使用字段访问可能更清晰 B
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));
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));
public final double x;
public final double y;