Подтвердить что ты не робот

О статических конечных ключевых словах в Java

В соответствии с учебным пособием:

Модификатор static в сочетании с модификатором final также используется для определения констант. Модификатор final указывает, что значение этого поля не может быть изменено.

Я согласен с этим только в том случае, если типы были примитивными. С ссылочными типами, например. экземпляр класса Point2D, где его атрибуты позиции не были final (т.е. мы могли бы изменить его положение), атрибуты такого типа переменных, такие как public static final Point2D A = new Point2D(x,y);, все еще могут быть изменены. Это правда?

4b9b3361

Ответ 1

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

public class Final {
    static final Point p = new Point();
    public static void main(String[] args) {
        p = new Point(); // Fails
        p.b = 10; // OK
        p.a = 20; // Fails
    }
}

class Point {
    static final int a = 10;
    static int b = 20;
}

Groovy (альтернативный JVM) имеет аннотацию, называемую @Immutable, которая блокирует изменение внутреннего состояния объекта после его создания.

Ответ 2

Правильно, он все равно может быть изменен. "Статический окончательный", в данном случае, относится к самой ссылке, которая не может быть изменена. Однако, если объект, являющийся ссылкой, изменен, тогда объект, который он ссылается, может быть изменен.

Неизменяемый объект, такой как String, будет константой.

Ответ 3

public static final Point2D A = new Point2D(x,y);

Здесь ссылка A окончательная и не значения внутри класса Point2D.

Вы не можете сделать это после определения статического финала:

//somewhere else in code
A = new Point2D(x1,y1);

Ответ 4

public static final Point2D A = новый Point2D (x, y); все еще можно изменить. Это правда?

Ссылка A не может быть изменена, но ее истинное значение объекта может быть изменено, если атрибуты не являются окончательными.

class Point2D{
  private int x;
  private int y;
  <getter & setter>
} 
class Constant{
  Public static final Point2D A = new Point2D(1,2);
  public static void main(String[] args){
     A.setX(10); // this will work 
     A = new Point2D(10,20);// this will not work
  }
}

В случае, если атрибуты Point2D's являются окончательными, тогда Point2D class будет immutable.

или вы можете отправить объект, способный клонировать.

Вроде -

 private static final Point2D A = new Point2D(x,y);
 public static getA(){
     return A.clone();
 }

Ответ 5

Это правда. Модификатор final не является транзитивным каким-либо возможным способом.

Это означает, что ссылка не изменится. Содержимое ссылки (поля объекта) может меняться со временем.

Ответ 6

Ссылка на точку (A в вашем случае) не может измениться. Только состояние объекта может измениться. Таким образом, вы не можете создать новый Point2D и назначить его переменной.

Ответ 7

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

Ответ 9

Здесь вы можете найти очень похожий вопрос с неплохим объяснением:

ЗДЕСЬ: Почему окончательный объект может быть изменен?

Кстати, я начал думать о механизме отражения....

в теории... Я верю, что вы можете получить экземпляр класса владельца.. затем получить члены класса, найти текущий экземпляр и проверить его окончательный....

Я не проверял его, и я не могу даже придумать, если это возможно - это просто идея (может быть?)

в

public class Final {
    static final Point p = new Point();

    public static void main(String[] args) throws MyImmutableException {
        p = new Point(); // Fails
        p.setB(10); // OK
        p.setA(20); // Fails - throws MyImmutableException
    }
}       

public class Point() {
    int a = 10;
    int b = 20;

    public setA(int a) {
        this.a = a;
    }
    public setB(int b) throws MyImmutableException {
        detectIsFinal()
        this.b = b;
    }

    private void detectIsFinal() throws MyImmutableException {
        int mod = this.getClass().getModifiers()
        if (Modifier.isFinal(mod)) {
            throw new MyImmutableException();
        }
    }   
}

public class MyImmutableException extends Exception { 
    public MyImmutableException() {super(); }
}

Я думал, что еще вы можете сделать... снова это просто!!!!!!!!! PSEUDOCODE!!! Я не уверен, будет ли это работать: P

Возможно, кто-то, кто знает аннотации, будет вдохновлен и заставит его работать. К сожалению, на этой неделе у меня больше нет времени. Возможно, позже я постараюсь сделать POC.

public class Final {
    @Immutable
    static final Point p = new Point();

    public static void main(String[] args)  {
        p = new Point(); // Fails
        p.setB(10); // Fails
        p.setA(20); // OK
    }
}       

public class Point() {
    int a = 10;
    @ImmutableOnThisInstance
    int b = 20;

    @DetectIsImmutable
    public setA(int a) {            
        this.a = a;
    }

    @DetectIsImmutable
    public setB(int b) {
        this.b = b;
    }      
}


class Immutable {
    ?????????????????
}

class DetectIsImmutable {
    /**
     * Just a pseudocode - I don't know how to work with ANNOTATIONS :) :) :)
     * SORRY :)
     * @throws MyImmutableException
     */
    private void detectMethod() throws MyImmutableException {
        Immutable instance = CLASS_THAT_IS_ANNOTATED.getClass().getAnnotation(Immutable.class)
        if (instance != null) {
            // get parent Method invocation name (from stacktrace list)
            String methodName = .............;
            if (methodName.startsWith("set")) {
                // check id we have variable with this settername
                String fieldName = ...; // cut "set" get rest of it, make first letterSmall 
                // find this field in object fields
                Field f = this.getClass().getDeclaredField(fieldName);
                if (f.getAnnotation(ImmutableOnThisInstance.class) != null) {
                    throw MyImmutableException();
                }
            }
        }
    }           

}

Ответ 10

Это все еще так.

Существует способ, которым претензия, которую вы цитируете, верна. static final описывает переменную, и это правда, что эта переменная не может измениться, и, следовательно, является константой. Переменная - это указатель на объект, и этот объект может измениться. Но это не мешает переменной быть константой.

Это менее мощный способ быть правдой, который можно достичь с помощью const в С++, но это что-то.

Ответ 11

Да, вы правы. Ссылка не может быть изменена, но объект, на который ссылаются, может быть. Что-то вроде этого совершенно законно:

public static final List<Object> someList = new ArrayList<Object>();

// ...

someList.add(someThing); // <-- this would be illegal if the referenced object was also constant

Ответ 12

Вы можете изменить свойства Point2D, но не создавать его новый экземпляр.

Я также должен указать, что Point2D является абстрактным, поэтому вы должны создать экземпляр дочернего класса, который расширяет его.

Ответ 13

Как уже упоминалось, ссылка на ваш объект Point2D статична, а не атрибуты x и y. Если вы хотите, чтобы вы не могли изменить положение объекта Point2D, вы должны установить атрибуты x и y статические и окончательные (инициализированные) в классе Point2D.

Ответ 14

static final Point2D A = new Point2D(x,y);

Все, что он говорит, это ссылка класса Point2D не может быть изменена.

            _____________
           |             |
A----------|--->(x,Y)    |
           |             | 
           |_____________|Heap

Таким образом, вы не можете изменить A, указав на другой объект, но, конечно, вы можете изменить значение (x, y) или содержимого объекта Point

Если вы хотите сделать свой объект также постоянным, вам придется сделать объект Point неизменным.

Ответ 15

Когда ссылочная переменная объявляется окончательной, вы не можете повторно назначить ей новый объект, когда он ссылается на объект. Но вы можете изменить состояние объекта, на который указывает конечная ссылочная переменная. Посмотрите на приведенный ниже пример.

class A
{
    int i = 10;
}

public class UseOfFinalKeyword
{
    public static void main(String[] args)
    {
        final A a = new A();  //final reference variable

        a.i = 50;
        //you can change the state of an object to which final reference variable is pointing

        a = new A();  //compile time error

        //you can't re-assign a new object to final reference variable
    }
}

Для получения дополнительной информации перейдите по ссылке: конечное ключевое слово в java