Как создать глубокий неизменяемый класс в Java?

#java #immutability

#java #неизменяемость

Вопрос:

Я хочу создать глубоко неизменяемую точку с плавающей точкой x и плавающей точкой y, вот мой код:

 public final class Point {
    private final float x;
    private final float y;

    //getter
    public float getX(){return x;}
    public float getY(){return y;}
    
    //constructor
    Point(float x,float y){this.x = x;this.y = y;}
    
    //equals
    public boolean equals(Point p1) {
        if (p1 == this) {return true;}
        Point p = p1;
        return Float.compare(x, p.x) == 0
                amp;amp; Float.compare(y, p.y) == 0; 
    }
    
    //toString
    public String toString() {
        return "x="   x   " y="   y;    
    }   
  

Однако, когда я тестировал, я обнаружил, что могу назначить новую точку существующей точке:

 public static void main(String[] args) {
    Point p1 = new Point(0,0);
    Point p2 = new Point(0,0);
    Point p3 = new Point(0,1);
    p1 = p3; //This operation is working, so it is not immutable.
    System.out.println(p1);
    System.out.println(p1.equals(p2));
}
  

Что я сделал не так? Как его улучшить? Спасибо!

Комментарии:

1. Point глубоко неизменяемый. Проблема заключается в вашем понимании переменных Java: любая переменная типа Point всегда является ссылкой на Point объект и может быть изменена (если не помечена final ).

2. Если вы используете final Point p1 = new Point(0,0); попытку переназначения p1 , это приведет к ошибке компиляции error: cannot assign a value to final variable p1 .

3. Point класс не имеет глубины , поэтому обсуждение глубокой неизменяемости бессмысленно (каламбур).

Ответ №1:

Ваш Point класс уже глубоко неизменяемый!

  p1 = p3; //This operation is working, so it is not immutable.
  

Неверно. Вы все еще можете переназначать переменные неизменяемых типов. Вот почему они называются переменными. Вы можете изменить то, что они хранят. Вы можете изменить p1 его так, чтобы он сохранял ссылку на другой Point объект, но чего вы не можете сделать, так это изменить свойства (например, координаты X или Y) Point объекта, на который p1 ссылается.

Чтобы сделать так, чтобы вы не могли изменять значение переменной, вы должны создать переменную final :

 final Point p1 = ...;
  

Вы можете написать тот же код с String помощью s, которые, как известно, являются неизменяемыми. Вы бы сказали, что String s тоже изменчивы? 🙂

 String p1 = "a";
String p2 = "b";
String p3 = "c";
p1 = p3; // this operation is working, does this mean that strings are mutable? No!
System.out.println(p1);
System.out.println(p1.equals(p2));
  

Ответ №2:

То, как вы его разработали, Point уже глубоко неизменяемо.

Когда вы выполняете присваивание p1 = p3 , вы не изменяете сам Point объект, вы просто меняете, на какой объект ссылается переменная.

Если вы не хотите, чтобы переменные переназначались, пометьте их следующим final образом:

 final Point p1 = new Point(0,0);
final Point p2 = new Point(0,0);
final Point p3 = new Point(0,1);
p1 = p3; // This won't work now
  

Ответ №3:

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

second..java является строго типизированным lenguage ..тогда, если вы создали переменную того же типа. вы могли бы заменить его (в этом примере p1 = p3 ) обе переменные являются классом Point .

с уважением!