用getter和setter调用实例属性好不好?
Is it good to call instance attributes using getter and setter?
我正在制作一款战舰 java 游戏,在整个过程中我都使用点 class 来存储 X 和 Y 坐标。我知道 getter 和 setter 如何工作以及我们为什么使用它们,但是这个特定的 class 同时具有 getter 和 public 属性所以这是我的问题,使用什么更好?
p.x 或 p.getX()
我知道使用 getter 是一种很好的做法,但在这种情况下我很困惑,我应该使用什么?
那个点 class 是一个古老的、过时的遗迹,是各种非惯用语 java。最初的错误是首先使用它;您的代码可能与 java.awt
无关,因此使用该包中的 class 并不是一个好主意。即使是,class 在这一点上只是一个错误,但不幸的是它的文档没有指出这一点。
鉴于已经犯了错误,问题'which one of these 2 things are better style'基本上没有实际意义:两者都不好。
如果您必须在这里抛硬币,请选择 .getX()
,它至少看起来更地道。
如果你有时间,自己做点class。它应该看起来像:
@Value public class Point {
int x, y;
}
或
public record Point(int x, y) {
}
或
public class Point {
private final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override public int hashCode() {
return (x * 31) ^ y;
}
@Override public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof Point)) return false;
Point p = (Point) other;
return p.x == x && p.y == y;
}
@Override public String toString() {
return String.format("[%d, %d]", x, y);
}
}
考虑到第三个选项中的文字墙,前两个选项中的一个可能更好。第一个使用 Project Lombok 来避免样板,第二个使用一个你不能真正使用的功能,除非你安装了 Java16。
注意:众所周知,我为 Lombok 做出了贡献 :)
NB2:java.awt.Point 不会改变的原因是因为现有代码会有 p.x = 5;
或其他地方,因此,像这样改变它(使其不可变)会破坏现有代码,java 不会这样做,除非有非常强烈的缓解理由。
如果您在设置属性时进行了一些修改,例如散列或加密
,你应该在 private
中制作这些属性,使用 getter
和 setter
,否则,只需在 public
.
中制作你的属性
(回顾一下,这是关于不可变对象与直接改变原始位置值的对比)
我不得不反驳@rzwitserloot 的回答。他提供了三个有问题的 classes:
- 第一个,Lombok,要么也是不可变的,要么使用@NonFinal 或@PackagePrivate 注释,因此使用 (creating/allowing) 未经检查的 getter 和 setter。因此,当谈到代码的安全性时,要么存在不可变性问题,要么与(可直接访问的)public 成员变量处于同一级别。
- 第二个,记录,浅层不可变。这意味着不能对 Point 本身对位置进行任何更改,但每次都必须创建一个新的 Point 实例
- 第三个,与第二个非常相似,是真正不可变的class。同样在这里:对位置的任何更改都不能对 Point 本身进行,但是每次都必须创建一个新的 Point 实例
所以我们在这里看到的是:不变性。如果你想让你的代码干净整洁,不变性很好。特别是调试。不变性是编写干净软件的好工具。修补匠的梦想。但是对于动手能力强的人来说,在某些情况下,这很快就变成了'overengineering'。
但是在性能方面存在一些问题:
- 对于不可变 class 的每次更改,您都必须创建该 class 的副本,并进行一些更改
- 很难只更改一个 aspect/value,然后在不创建多个对象的情况下更改另一个值
所以,假设一个愚蠢的 JVM,
- 您很快就会 运行 陷入基于内存的性能问题,因为您需要创建所有这些对象
- 速度比简单地更改值要慢得多。
很高兴,JVM 非常聪明:
- 在短暂的 运行 时间后,JIT finds/knows class 被使用和丢弃并对其进行优化。
- 此外,通过 getters/setters 访问要慢很多,但在大多数情况下,JVM 也可以消除其中的大部分。
此外,随着 JVM 每年都在进步,optimization/speed 可能会进一步增加,从而减少甚至消除不可变 classes 的任何缺点。此外,优化肯定会更安全,或者至少与您设计的任何东西一样安全。但它们能同样高效吗?
BUT 也有 JVM 无法进行任何优化的情况。尤其是当涉及 interfaces/abstract base classes 时,即使是方法调用也会变慢,因为真正的目标方法的地址必须在 运行 时间解析,每一次。
所以最后,由您来测试并决定要使用哪种方法。
如果这一点额外的安全性真的值得 'drop' 的性能。
关于 JVM 优化,您对未来有多少期望。
其他人说得对的地方:不要使用 AWT classes 除非你真的在使用 AWT。最好有自己的 class 来满足您的需求。
// 大更新:
最后要考虑的一件事,IMO 是使用不可变 Position 类型的最大缺点:
(警告:这个例子会变得越来越荒谬!但它显示了该策略的导向)
- 假设我们有以下 Class:
class Ship { Position position; }
- 所以我们通过
ship.position
解决这个问题
- 现在,当我们想要改变船的位置时,我们必须改变对位置的引用:
ship.position = ... (new Position or ship.position.clone(newX,newY) or ship.position.with(newX,newY)
- 所以每当我们想改变船的位置,并遵循不变性模式
-
- 半结果:我们至少需要另一个 getter/setter 作为船上的位置
-
-
- 任何处理位置的东西也必须知道它包含 Classes,例如 Ship 和任何和所有其他有位置的东西并且可能由相同的逻辑计算(是的,接口,但是那在哪里停止?)
-
-
- 此外,您还必须每次检查 Ship.position 是否不为空...
-
- 完全因此:船舶也应该是不可变的,并且在其位置或任何其他状态发生任何变化时,场景中的船舶将被一个静音的不可变副本所取代。
-
-
- 此外,如果发生任何更改,都必须替换方案。哇
-
-
-
- 任何使用飞船的东西都必须知道飞船的所有引用,所以它可以更新那些
-
-
-
- 如果场景发生变化,游戏也应该是不可变的并且它的实例必须被替换..等等,什么?
-
-
- 所以我们看到存在很多不可变对象不是好的解决方案的场景
我正在制作一款战舰 java 游戏,在整个过程中我都使用点 class 来存储 X 和 Y 坐标。我知道 getter 和 setter 如何工作以及我们为什么使用它们,但是这个特定的 class 同时具有 getter 和 public 属性所以这是我的问题,使用什么更好?
p.x 或 p.getX()
我知道使用 getter 是一种很好的做法,但在这种情况下我很困惑,我应该使用什么?
那个点 class 是一个古老的、过时的遗迹,是各种非惯用语 java。最初的错误是首先使用它;您的代码可能与 java.awt
无关,因此使用该包中的 class 并不是一个好主意。即使是,class 在这一点上只是一个错误,但不幸的是它的文档没有指出这一点。
鉴于已经犯了错误,问题'which one of these 2 things are better style'基本上没有实际意义:两者都不好。
如果您必须在这里抛硬币,请选择 .getX()
,它至少看起来更地道。
如果你有时间,自己做点class。它应该看起来像:
@Value public class Point {
int x, y;
}
或
public record Point(int x, y) {
}
或
public class Point {
private final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override public int hashCode() {
return (x * 31) ^ y;
}
@Override public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof Point)) return false;
Point p = (Point) other;
return p.x == x && p.y == y;
}
@Override public String toString() {
return String.format("[%d, %d]", x, y);
}
}
考虑到第三个选项中的文字墙,前两个选项中的一个可能更好。第一个使用 Project Lombok 来避免样板,第二个使用一个你不能真正使用的功能,除非你安装了 Java16。
注意:众所周知,我为 Lombok 做出了贡献 :)
NB2:java.awt.Point 不会改变的原因是因为现有代码会有 p.x = 5;
或其他地方,因此,像这样改变它(使其不可变)会破坏现有代码,java 不会这样做,除非有非常强烈的缓解理由。
如果您在设置属性时进行了一些修改,例如散列或加密
,你应该在 private
中制作这些属性,使用 getter
和 setter
,否则,只需在 public
.
(回顾一下,这是关于不可变对象与直接改变原始位置值的对比)
我不得不反驳@rzwitserloot 的回答。他提供了三个有问题的 classes:
- 第一个,Lombok,要么也是不可变的,要么使用@NonFinal 或@PackagePrivate 注释,因此使用 (creating/allowing) 未经检查的 getter 和 setter。因此,当谈到代码的安全性时,要么存在不可变性问题,要么与(可直接访问的)public 成员变量处于同一级别。
- 第二个,记录,浅层不可变。这意味着不能对 Point 本身对位置进行任何更改,但每次都必须创建一个新的 Point 实例
- 第三个,与第二个非常相似,是真正不可变的class。同样在这里:对位置的任何更改都不能对 Point 本身进行,但是每次都必须创建一个新的 Point 实例
所以我们在这里看到的是:不变性。如果你想让你的代码干净整洁,不变性很好。特别是调试。不变性是编写干净软件的好工具。修补匠的梦想。但是对于动手能力强的人来说,在某些情况下,这很快就变成了'overengineering'。
但是在性能方面存在一些问题:
- 对于不可变 class 的每次更改,您都必须创建该 class 的副本,并进行一些更改
- 很难只更改一个 aspect/value,然后在不创建多个对象的情况下更改另一个值
所以,假设一个愚蠢的 JVM,
- 您很快就会 运行 陷入基于内存的性能问题,因为您需要创建所有这些对象
- 速度比简单地更改值要慢得多。
很高兴,JVM 非常聪明:
- 在短暂的 运行 时间后,JIT finds/knows class 被使用和丢弃并对其进行优化。
- 此外,通过 getters/setters 访问要慢很多,但在大多数情况下,JVM 也可以消除其中的大部分。
此外,随着 JVM 每年都在进步,optimization/speed 可能会进一步增加,从而减少甚至消除不可变 classes 的任何缺点。此外,优化肯定会更安全,或者至少与您设计的任何东西一样安全。但它们能同样高效吗?
BUT 也有 JVM 无法进行任何优化的情况。尤其是当涉及 interfaces/abstract base classes 时,即使是方法调用也会变慢,因为真正的目标方法的地址必须在 运行 时间解析,每一次。
所以最后,由您来测试并决定要使用哪种方法。 如果这一点额外的安全性真的值得 'drop' 的性能。 关于 JVM 优化,您对未来有多少期望。
其他人说得对的地方:不要使用 AWT classes 除非你真的在使用 AWT。最好有自己的 class 来满足您的需求。
// 大更新:
最后要考虑的一件事,IMO 是使用不可变 Position 类型的最大缺点:
(警告:这个例子会变得越来越荒谬!但它显示了该策略的导向)
- 假设我们有以下 Class:
class Ship { Position position; }
- 所以我们通过
ship.position
解决这个问题
- 现在,当我们想要改变船的位置时,我们必须改变对位置的引用:
ship.position = ... (new Position or ship.position.clone(newX,newY) or ship.position.with(newX,newY)
- 所以每当我们想改变船的位置,并遵循不变性模式
-
- 半结果:我们至少需要另一个 getter/setter 作为船上的位置
-
-
- 任何处理位置的东西也必须知道它包含 Classes,例如 Ship 和任何和所有其他有位置的东西并且可能由相同的逻辑计算(是的,接口,但是那在哪里停止?)
-
-
-
- 此外,您还必须每次检查 Ship.position 是否不为空...
-
-
- 完全因此:船舶也应该是不可变的,并且在其位置或任何其他状态发生任何变化时,场景中的船舶将被一个静音的不可变副本所取代。
-
-
- 此外,如果发生任何更改,都必须替换方案。哇
-
-
-
-
- 任何使用飞船的东西都必须知道飞船的所有引用,所以它可以更新那些
-
-
-
-
-
- 如果场景发生变化,游戏也应该是不可变的并且它的实例必须被替换..等等,什么?
-
-
-
-
- 所以我们看到存在很多不可变对象不是好的解决方案的场景
-