Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的类结构对象_Java_Oop_Struct - Fatal编程技术网

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; } 第一个示例中的

创建类似结构的对象是否完全违背了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;
}
第一个示例中的类非常方便

// 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;