我可以制作一个行为类似于原始类型的类吗?

时间:2019-04-22 13:08:03

标签: java oop

我制作了一个Point类来管理xy坐标(我知道一些Java默认程序包已经具有一些以类似方式运行的Point对象,我将其用作惰性选择,这是一个示例,请不要介意^^ )。

在使用它之前,我使用的是int基本类型。

事情是,当将类或原始类型作为方法的参数传递时,两者的行为方式不同,如果我在方法中更改原始变量的值,则原始变量不会受到影响,这与我使用的是对象,因为它是作为参数传递的引用。

我的问题是,由于我使用Point进行数学运算(下面的示例),因此我必须手动创建新对象以保存结果,并且我从不使用它在两个变量之间建立“链接”,就像对象行为一样通常。

我的积分课程:

public class Point {
    public int x;
    public int y;

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

    public Point() {
        this(0, 0);
    }
}

方法示例:

public Point getAdjacent(int x, int y, Direction dir) {
        Point pt = new Point(x, y);//basically, i would like to do that automatically
        switch (dir) {
        case Up:
            pt.y -= 1;
            break;
        case Down:
            pt.y += 1;
            break;
        case Right:
            pt.x -= 1;
            break;
        case Left:
            pt.x += 1;
            break;
        default:
            //do nothing
        }
        return pt;
    }

总而言之,是否可以使Point表现得像原始类型?

编辑:我的意思是当它作为参数传递或执行point1 = point2

时,它将自动复制它

2 个答案:

答案 0 :(得分:1)

首先::请确保在切换代码中使用break语句。否则,当大小写匹配时,切换块将“掉线”并执行:

pt.y -= 1; 
pt.y += 1;
pt.x -= 1;
pt.x += 1;

(参考:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html


根据问题,您确实可以使用Point类。下面的代码将:
 1.使用一个点作为输入。
 2.从输入Point中将变量x和y提取到复制基元中。
 3.更改复制的基元。
 4.根据副本创建一个新的Point。

这样,“旧”点将保持不变。

public Point getAdjacent(final Point point, final Direction dir) {
    int x = point.x;
    int y = point.y;
    switch (dir) {
        case Up:
            y -= 1;
            break;
        case Down:
            y += 1;
            break;
        case Right:
            x -= 1;
            break;
        case Left:
            x += 1;
            break;
        default:
            break;
    }
    return new Point(x, y);
}

答案 1 :(得分:0)

这个问题可能有点太广泛了,因为人们可能会对“行为”一词的含义进行广泛的争论。但是在某种程度上,我们可以解决这个问题:

最短的答案可能是:否,这不可能。

一个更为详尽的答案可能是:不,还不可能让一个类(或更确切地说是一个对象)表现得像一个原始值。


长答案:

我们正在努力实现可能与您要实现的目标接近的行为。此处的相关关键字是值类型

一些资源:

但是,当前版本的Java和JVM不支持此功能,并且可能需要一段时间才能整理出详细信息。

直到那时,仍有一些可行的解决方法可以实现预期的目标。

最简单的解决方案是您已经提出的解决方案:您总是返回一个新实例,而不是修改给定的对象。

您在问题中显示的示例可能不是最好的例子,因为您显示的方法getAdjacent实际上可能是static方法。它不使用以任何方式调用它的实例。

然后,您始终可以确定每次修改都收到一个新实例。否则,请想象以下代码片段:

Point a = new Point(1,2);
Point b = new Point(3,4);

a.add(b);

System.out.println(a); // What does this print?

取决于add方法的实现,其行为可能不清楚。如果是这样实现的:

public void add(Point other) {
    this.x += other.x;
    this.y += other.y;
}

然后将修改点a,输出将为(4,6)

但是如果是这样实现的

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

然后a不会受到影响,并且输出仍然是(1,2)

通常,制作Point 不可变之类的东西基本上可以实施这种编程风格。因此,您可以在类x中创建变量yfinal,以便始终确保对象在创建后不能被修改:

public class Point {

    // Note that these are FINAL:   
    private final int x; 
    private final int y;

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

对于类似Point类(我在this answer中提到过的类)这样看似微不足道的东西,还有一些其他设计方面的考虑,但是讨论这些问题不在此答案的范围之内。 >