Setter params final в Java

Я всегда программировал на java, и недавно я начал изучать некоторые c++.

В C++ принято устанавливать параметры setter как const, почему мы не видим этого так много в java ?

Я имею в виду, есть ли какие-либо недостатки в создании сеттера, например:

public void setObject(final Object o){ this.o=o; }

vs

public void setObject(Object o){ this.o=o; }

первый должен принудительно для объекта param o оставаться постоянным через всю функцию набора, не так ли ?

Edit:

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

public void setName(String name){ 
     name="Carlos";
     this.name=name; 
}

пользователь никогда не сможет установить имя, отличное от"Carlos"

2 ответов


хорошо,final параметр / переменная не могут быть назначены. Поскольку компилятор java должен быть способен определить, является ли переменная / параметр на самом деле final (для анонимных внутренних классов), оптимизация не является фактором AFAIK.

это больше, что C++ имеет больший набор инструментов, который java пытался уменьшить. Следовательно, используя C++ const string& важно, говоря

  1. строка передается указателем, доступ осуществляется автоматически разыменованный.
  2. если фактический аргумент является переменной, сама переменная не изменяется.
  3. имейте в виду, что может быть оператор преобразования для передачи чего-то другого, чем const string&.

теперь java:

  1. Java не выделяет объекты в стеке, только сохраняет примитивные типы и дескрипторы объектов в стеке.
  2. Java не имеет выходных параметров: переменная, переданная вызову метода, никогда не изменит свой немедленный значение.

возвращаясь к вашему вопросу:

как сеттер в java в основном не выиграет от конечного параметра. Окончательным будет контракт, чтобы не использовать переменную для второго назначения.

:
public final void setXyz(Xz xyz) {
    this.xyz = xyz;
}

полезнее: этот метод не может быть переопределен, и, следовательно, может безопасно использоваться в конструкторе. (Вызов переопределенного метода в конструкторе будет происходить в контексте все еще не инициализированного дочернего экземпляра.)


мало преимуществ в установке параметра метода Java как окончательного, так как это не останавливает кого-то от изменения состояния ссылки на параметр в методе. Все, что он предотвращает, это повторное присвоение переменной параметра чему-то другому, что ничего не делает с исходной ссылкой, и позволяет использовать параметр в анонимных внутренних классах. Если вам нужна истинная безопасность в этой ситуации, вы попытаетесь сделать ваши типы параметров неизменяемыми, если вероятный.


редактировать
Вы писали:

public void setObject(Object o){ 
     o++; // this does not compile
     this.o=o; 
}

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

private void setI(final Integer i) {
   this.i = 1 + i;
}

но ни ваш код, ни этот код выше не повлияют на объект параметра на стороне вызывающего кода.


редактировать
ОК теперь вы писали:

public void setName(String name){ 
     name="Carlos";
     this.name=name; 
}

но тогда кто-то мог бы написать

public void setName(final String name){ 
     this.name= name + " Carlos"; 
}

вот где опасность приходит и где финал не помогает. Скажем, у вас есть класс под названием Name:

public class Name {
   private String lastName;
   private String firstName;
   public Name(String lastName, String firstName) {
      this.lastName = lastName;
      this.firstName = firstName;
   }
   public String getLastName() {
      return lastName;
   }
   public void setLastName(String lastName) {
      this.lastName = lastName;
   }
   public String getFirstName() {
      return firstName;
   }
   public void setFirstName(String firstName) {
      this.firstName = firstName;
   }
}

а затем класс, Foo, с полем имени и сеттером. Это опасно код:

class Foo {
   private Name name;

   public void setName(final Name name) {
      name.setFirstName("Carlos");
      this.name = name;
   }
}

потому что он не только изменяет состояние поля, он изменяет состояние ссылки на имя в вызывающем коде и финал модификатор не поможет ни на йоту. Решение: сделать имя неизменяемым.

например,

import java.util.Date;

// class should be declared final
public final class BetterName {
   private String lastName;
   private String firstName;
   private Date dateOfBirth;

   public BetterName(String lastName, String firstName, Date dob) {
      this.lastName = lastName;
      this.firstName = firstName;

      // make and store a private copy of non-immutable reference types
      dateOfBirth = new Date(dob.getTime()); 
   }

   // only getters -- no setters
   public String getLastName() {
      return lastName;
   }

   public String getFirstName() {
      return firstName;
   }

   public Date getDateOfBirth() {
      // return copies of non-immutable fields
      return new Date(dateOfBirth.getTime());
   }
}