Могу ли я сделать класс, который ведет себя как примитивный тип? - PullRequest
0 голосов
/ 22 апреля 2019

Я создал класс Point для управления координатами xy (я знаю, что в некоторых java-пакетах по умолчанию уже есть некоторый объект Point, который ведет себя аналогичным образом, я использую его как альтернативу lazy, и это пример, пожалуйста, не возражайте против этого ^^).

Перед его использованием я использовал тип примитива int.

Дело в том, что при передаче класса или типа примитива в качестве параметра метода оба не действуют одинаковоЕсли я изменю значение примитивной переменной в методе, исходная переменная не изменится, в отличие от того, использовал ли я объект, поскольку его ссылка передается как параметр.

Моя проблема заключается в том, что, поскольку я использую объектТочка для математики (пример ниже), я должен вручную создать новый объект, чтобы сохранить результат, и я никогда не использую его, чтобы иметь «связь» между двумя переменными, как я мог бы с тем, как обычно ведет себя объект.

Моя точкакласс:

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 ]

1 голос
/ 22 апреля 2019

Прежде всего: обязательно используйте операторы break в вашем коде коммутатора. В противном случае при совпадении с регистром Up блок переключателя «провалится» и выполнит:

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. Извлеките переменные x и y из входной точки в примитив копирования.
3. Измените скопированные примитивы.
4. Создайте новую точку на основе копий.

Таким образом, «старая» точка останется нетронутой.

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);
}
0 голосов
/ 22 апреля 2019

Вопрос может быть слишком широким, потому что можно довольно широко спорить о том, что должно означать слово «вести себя». Но в некоторой степени мы можем разобраться в этом:

Самый короткий ответ может быть: Нет, это невозможно.

Немного более сложный ответ может быть: Нет, это не пока невозможно позволить классу (или, точнее, объекту) вести себя как примитивное значение.


Длинный ответ:

Существуют усилия для достижения поведения, которое может приблизиться к тому, что вы пытаетесь достичь. Соответствующее ключевое слово здесь Типы значений .

Некоторые ресурсы:

Однако это не поддерживается в текущих версиях 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 и y в своем классе final, чтобы вы всегда могли быть уверены, что объект не может быть изменен после его создания:

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 класс (некоторые из которых я упомянул в этом ответе ), но их обсуждение выходит за рамки этого ответа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...