Java 中的结构类对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:27:58  来源:igfitidea点击:

Struct like objects in Java

javaoopstruct

提问by Chris de Vries

Is it completely against the Java way to create struct like objects?

是否完全违背了创建类似对象的结构的 Java 方式?

class SomeData1 {
    public int x;
    public int y;
}

I can see a class with accessors and mutators being more Java like.

我可以看到一个带有访问器和修改器的类更像 Java。

class SomeData2 {
    int getX();
    void setX(int x);

    int getY();
    void setY(int y);

    private int x;
    private int y;
}

The class from the first example is notationally convenient.

第一个示例中的类在符号上很方便。

// a function in a class
public int f(SomeData1 d) {
    return (3 * d.x) / d.y;
}

This is not as convenient.

这不是那么方便。

// a function in a class
public int f(SomeData2 d) {
    return (3 * d.getX()) / d.getY();
}

采纳答案by Bartosz Bierkowski

This is a commonly discussed topic. The drawback of creating public fields in objects is that you have no control over the values that are set to it. In group projects where there are many programmers using the same code, it's important to avoid side effects. Besides, sometimes it's better to return a copy of field's object or transform it somehow etc. You can mock such methods in your tests. If you create a new class you might not see all possible actions. It's like defensive programming - someday getters and setters may be helpful, and it doesn't cost a lot to create/use them. So they are sometimes useful.

这是一个经常讨论的话题。在对象中创建公共字段的缺点是您无法控制为其设置的值。在许多程序员使用相同代码的团队项目中,避免副作用很重要。此外,有时最好返回字段对象的副本或以某种方式对其进行转换等。您可以在测试中模拟此类方法。如果您创建一个新类,您可能看不到所有可能的操作。这就像防御性编程 - 有一天 getter 和 setter 可能会有所帮助,并且创建/使用它们不会花费太多。所以它们有时很有用。

In practice, most fields have simple getters and setters. A possible solution would look like this:

实际上,大多数字段都有简单的 getter 和 setter。一个可能的解决方案如下所示:

public property String foo;   
a->Foo = b->Foo;

Update: It's highly unlikely that property support will be added in Java 7 or perhaps ever. Other JVM languages like Groovy, Scala, etc do support this feature now. - Alex Miller

更新:在 Java 7 中或以后添加属性支持的可能性很小。其他 JVM 语言(如 Groovy、Scala 等)现在确实支持此功能。- 亚历克斯·米勒

回答by John Topley

I don't see the harm if you know that it's always going to be a simple struct and that you're never going to want to attach behaviour to it.

如果您知道它始终是一个简单的结构并且您永远不想将行为附加到它,那么我看不出有什么危害。

回答by brabster

If the Java way is the OO way, then yes, creating a class with public fields breaks the principles around information hiding which say that an object should manage its own internal state. (So as I'm not just spouting jargon at you, a benefit of information hiding is that the internal workings of a class are hidden behind an interface - say you wanted to change the mechanism by which your struct class saved one of its fields, you'll probably need to go back and change any classes that use the class...)

如果 Java 方式是 OO 方式,那么是的,创建具有公共字段的类打破了信息隐藏的原则,即对象应该管理自己的内部状态。(因此,我不只是在向您吐槽行话,信息隐藏的一个好处是类的内部工作隐藏在接口后面 - 假设您想更改结构类保存其中一个字段的机制,您可能需要返回并更改使用该类的任何类...)

You also can't take advantage of the support for JavaBean naming compliant classes, which will hurt if you decide to, say, use the class in a JavaServer Page which is written using Expression Language.

您也不能利用对 JavaBean 命名兼容类的支持,如果您决定在使用表达式语言编写的 JavaServer Page 中使用该类,这将受到伤害。

The JavaWorld article Why Getter and Setter Methods are Evilarticle also might be of interest to you in thinking about when not to implement accessor and mutator methods.

JavaWorld 文章为什么 Getter 和 Setter 方法是邪恶的文章也可能让您在思考何时不实现访问器和修改器方法时感兴趣。

If you're writing a small solution and want to minimise the amount of code involved, the Java way may not be the right way - I guess it always depends on you and the problem you're trying to solve.

如果您正在编写一个小型解决方案并希望最大限度地减少所涉及的代码量,那么 Java 方式可能不是正确的方式 - 我想这总是取决于您和您要解决的问题。

回答by Jonathan

This is a question on Object Oriented Design, not Java the language. It's generally good practice to hide data types within the class and expose only the methods that are part of the class API. If you expose internal data types, you can never change them in the future. If you hide them, your only obligation to the user is the method's return and argument types.

这是一个关于面向对象设计的问题,而不是 Java 语言。通常,在类中隐藏数据类型并仅公开属于类 API 的方法是一种很好的做法。如果您公开内部数据类型,您将永远无法更改它们。如果你隐藏它们,你对用户的唯一义务就是方法的返回和参数类型。

回答by Spoike

By the way, the structure you're giving as an example already exist in the Java base class library as java.awt.Point. It has x and y as public fields, check it out for yourself.

顺便说一句,您作为示例给出的结构已经存在于 Java 基类库中,如java.awt.Point. 它有 x 和 y 作为公共字段,自己检查一下

If you know what you're doing, and others in your team know about it, then it is okay to have public fields. But you shouldn't rely on it because they can cause headaches as in bugs related to developers using objects as if they were stack allocated structs (java objects are always sent to methods as references and not as copies).

如果您知道自己在做什么,并且团队中的其他人也知道,那么拥有公共字段就可以了。但是你不应该依赖它,因为它们会导致头痛,因为它们会导致与开发人员使用对象相关的错误,就好像它们是堆栈分配的结构一样(java 对象总是作为引用而不是作为副本发送到方法)。

回答by izb

Use common sense really. If you have something like:

真正使用常识。如果你有类似的东西:

public class ScreenCoord2D{
    public int x;
    public int y;
}

Then there's little point in wrapping them up in getters and setters. You're never going to store an x, y coordinate in whole pixels any other way. Getters and setters will only slow you down.

那么将它们包含在 getter 和 setter 中就没有什么意义了。您永远不会以任何其他方式以整个像素存储 x、y 坐标。getter 和 setter 只会减慢你的速度。

On the other hand, with:

另一方面,与:

public class BankAccount{
    public int balance;
}

You might want to change the way a balance is calculated at some point in the future. This should really use getters and setters.

您可能希望在将来的某个时候更改余额的计算方式。这应该真正使用 getter 和 setter。

It's always preferable to know whyyou're applying good practice, so that you know when it's ok to bend the rules.

最好知道为什么要应用良好的实践,这样你就知道什么时候可以改变规则。

回答by Mark Renouf

Re: aku, izb, John Topley...

回复:阿库,izb,约翰·托普利……

Watch out for mutability issues...

注意可变性问题...

It may seem sensible to omit getters/setters. It actually may be ok in some cases. The real problem with the proposed pattern shown here is mutability.

省略 getter/setter 似乎是明智的。在某些情况下实际上可能没问题。此处显示的提议模式的真正问题是可变性。

The problem is once you pass an object reference out containing non-final, public fields. Anything else with that reference is free to modify those fields. You no longer have any control over the state of that object. (Think what would happen if Strings were mutable.)

问题是一旦您将包含非最终公共字段的对象引用传递出去。带有该引用的任何其他内容都可以自由修改这些字段。您不再可以控制该对象的状态。(想想如果字符串是可变的会发生什么。)

It gets bad when that object is an important part of the internal state of another, you've just exposed internal implementation. To prevent this, a copy of the object must be returned instead. This works, but can cause massive GC pressure from tons of single-use copies created.

当该对象是另一个对象的内部状态的重要组成部分时,情况会变得很糟糕,您刚刚公开了内部实现。为了防止这种情况,必须返回对象的副本。这有效,但会导致大量创建的一次性副本产生巨大的 GC 压力。

If you have public fields, consider making the class read-only. Add the fields as parameters to the constructor, and mark the fields final. Otherwise make sure you're not exposing internal state, and if you need to construct new instances for a return value, make sure it won't be called excessively.

如果您有公共字段,请考虑将该类设为只读。将字段作为参数添加到构造函数中,并将字段标记为 final。否则请确保您没有公开内部状态,并且如果您需要为返回值构造新实例,请确保它不会被过度调用。

See: "Effective Java" by Joshua Bloch -- Item #13: Favor Immutability.

请参阅:Joshua Bloch 的“ Effective Java”——项目 #13:支持不变性。

PS: Also keep in mind, all JVMs these days will optimize away the getMethod if possible, resulting in just a single field-read instruction.

PS:还要记住,如果可能的话,现在所有的 JVM 都会优化掉 getMethod,导致只有一个字段读取指令。

回答by Brian

To address mutability concerns you can declare x and y as final. For example:

为了解决可变性问题,您可以将 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;
  }
}

Calling code that attempts to write to these fields will get a compile time error of "field x is declared final; cannot be assigned".

调用尝试写入这些字段的代码将得到“字段 x 被声明为最终的;无法分配”的编译时错误。

The client code can then have the 'short-hand' convenience you described in your post

然后,客户端代码可以具有您在帖子中描述的“简写”便利性

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();
    }
}

回答by Alex Miller

The problem with using public field access is the same problem as using new instead of a factory method - if you change your mind later, all existing callers are broken. So, from an API evolution point of view, it's usually a good idea to bite the bullet and use getters/setters.

使用公共字段访问的问题与使用 new 而不是工厂方法的问题相同——如果你以后改变主意,所有现有的调用者都会被破坏。因此,从 API 演变的角度来看,咬紧牙关使用 getter/setter 通常是个好主意。

One place where I go the other way is when you strongly control access to the class, for example in an inner static class used as an internal data structure. In this case, it might be much clearer to use field access.

我采取另一种方式的一个地方是当您强烈控制对类的访问时,例如在用作内部数据结构的内部静态类中。在这种情况下,使用字段访问可能会更清楚。

By the way, on e-bartek's assertion, it is highly unlikely IMO that property support will be added in Java 7.

顺便说一句,根据 e-bartek 的说法,IMO 极不可能在 Java 7 中添加属性支持。

回答by Kris Nuttycombe

I frequently use this pattern when building private inner classes to simplify my code, but I would not recommend exposing such objects in a public API. In general, the more frequently you can make objects in your public API immutable the better, and it is not possible to construct your 'struct-like' object in an immutable fashion.

我在构建私有内部类时经常使用这种模式来简化我的代码,但我不建议在公共 API 中公开此类对象。通常,您可以越频繁地使公共 API 中的对象不可变越好,并且不可能以不可变的方式构造您的“类结构”对象。

As an aside, even if I were writing this object as a private inner class I would still provide a constructor to simplify the code to initialize the object. Having to have 3 lines of code to get a usable object when one will do is just messy.

顺便说一句,即使我将此对象编写为私有内部类,我仍然会提供一个构造函数来简化代码以初始化对象。必须有 3 行代码才能获得一个可用的对象,这太麻烦了。