【问题标题】:Is it possible to overload operators in Java? [duplicate]是否可以在 Java 中重载运算符? [复制]
【发布时间】:2012-01-12 14:21:16
【问题描述】:

我有以下类,它描述了 XY 表面上的一个点:

class Point{
    double x;
    double y;

    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }
}

所以我想覆盖+- 运算符以便有可能编写运行以下代码:

Point p1 = new Point(1, 2);
Point p2 = new Point(3, 4);
Point resAdd = p1 + p2; // answer (4, 6)
Point resSub = p1 - p2; // answer (-2, -2)

如何在 Java 中做到这一点?或者我应该使用这样的方法:

public Point Add(Point p1, Point p2){
    return new Point(p1.x + p2.x, p1.y + p2.y);
}

提前致谢!

【问题讨论】:

    标签: java operator-overloading


    【解决方案1】:

    你不能在 Java 中做到这一点。您必须在 Point 类中实现 plusadd 方法。

    class Point{
        public double x;
        public double y;
    
        public Point(int x, int y){
            this.x = x;
            this.y = y;
        }
    
        public Point add(Point other){
            this.x += other.x;
            this.y += other.y;
            return this;
        }
    }
    

    用法

    Point a = new Point(1,1);
    Point b = new Point(2,2);
    a.add(b);  //=> (3,3)
    
    // because method returns point, you can chain `add` calls
    // e.g., a.add(b).add(c)
    

    【讨论】:

    • 在可变类中,更改现有实例是正常的,但将Point 设为不可变值会更好。
    • @TomHawtin-tackline 根据您的评论进行了编辑。
    • 另一个讨厌 Java 的理由 :(
    【解决方案2】:

    尽管你不能在纯 Java 中做到这一点,但你可以使用 java-oo compiler plugin 做到这一点。 您需要为 + 运算符编写 add 方法:

    public Point add(Point other){
       return new Point(this.x + other.x, this.y + other.y);
    }
    

    而 java-oo 插件只是对这些方法调用进行脱糖操作。

    【讨论】:

    • 当然这是一个愚蠢的想法,除非只有你会阅读你的代码
    【解决方案3】:

    Java 中没有运算符重载。显然是出于口味的原因。真可惜。

    (有些人会声称 Java 确实有重载,因为 +String 可能还有自动装箱/拆箱。)

    我们来谈谈值类型。

    许多早期的课程(以及后来的一些课程)都把这个弄得一团糟。特别是在 AWT 中。在 AWT 中,您应该在各处显式地复制简单值。几乎可以肯定你想让值类型不可变 - 类应该是 final 并且它不应该改变状态(通常所有 final 字段都指向有效的不可变对象)。

    所以:

    public final class Point {
        private final int x;
        private final int y;
    
        private Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public static of(int x, int y) {
            return new Point(x, y);
        }
    
        public int x() {
            return x;
        }
        public int y() {
            return y;
        }
        public Point add(Point other) {
            return of(x+other.x, y+other.y);
        }
    
        // Standard fluffy bits:
        @Override public int hashCode() {
            return x + 37*y;
        }
        @Override public boolean equals(Object obj) {
            if (!(obj instanceof Point)) {
                return false;
            }
            Point other = (Point)obj;
            return x==other.x && y==other.y;
        }
        @Override public String toString() {
            return "("+x+", "+y+")";
        }
    }
    

    原来的代码混淆了intdouble,所以我选择了一个。如果你使用了double,你应该排除NaN。 “点”往往暗示一个绝对点,添加没有意义。 “矢量”或“维度”可能更合适,具体取决于您的意图。

    我隐藏了构造函数,因为身份并不重要。可能值可以被缓存。例如,在零点上加一个点可能很常见,因此不需要创建点。

    您可能需要一个可变版本,例如用作累加器。这应该是一个没有继承关系的单独类。可能不是在简单的情况下,但无论如何我都会展示它:

    public final class PointBuilder {
        private int x;
        private int y;
    
        public PointBuilder() {
        }
        public PointBuilder(Point point) {
            this.x = point.x;
            this.y = point.y;
        }
        public Point toPoint() {
            return new Point(x, y);
        }
    
        public PointBuilder x(int x) {
            this.x = x;
            return this;
        }
        public PointBuilder y(int y) {
            this.y = y;
            return this;
        }
        public PointBuilder add(Point other) {
            this.x += other.x;
            this.y += other.y;
            return this;
        }
    }
    

    【讨论】:

      【解决方案4】:

      您不能在 Java 中执行此操作,因为 Java 中没有运算符重载。

      你必须使用你提到的第二个选项:

      编辑:您可以在 Point 类本身中添加Add 方法

      public Point Add(Point other){
          return new Point(this.x + other.x, this.y + other.y);
      }
      

      【讨论】:

      • 实现实例方法而不是类方法似乎更有意义。
      • 在可变类中,更改现有实例是正常的,尽管将Point 设为不可变值会更好。 (另外,add 中的 a 应该是小写。)
      【解决方案5】:

      您不能在 java 中重载运算符。您需要在 Point 类中处理此问题。

      【讨论】:

      • 那是,嗯,一个令人惊讶的构造函数。当然,你不会,说,想把它变成一个有名字的静态方法,比如sum
      • 嗯,有很多方法可以做到这一点。这里的底线是您不能覆盖运算符。
      【解决方案6】:

      您不能覆盖 Java 中的运算符。这就是为什么不应该在 Java 中实现任何非平凡的数学(尤其是几何)运算的原因之一(上面的 Point 类就是这样一个类,如果你想让它做一些真正的工作,例如一行行交叉点,你最好用 C++ 来做)。

      【讨论】:

        猜你喜欢
        • 2015-01-01
        • 2012-09-04
        • 2010-10-20
        • 2010-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-05
        相关资源
        最近更新 更多