La final de Java contra la const de C ++

El tutorial de Java para C ++ progtwigdores dice que (destacar es mío):

La palabra clave final es más o menos equivalente a const en C ++

¿Qué significa “aproximadamente” en este contexto? ¿No son exactamente lo mismo?

¿Cuáles son las diferencias, si las hay?

En C ++ marcar una función de miembro const significa que se puede const instancias const . Java no tiene un equivalente a esto. P.ej:

 class Foo { public: void bar(); void foo() const; }; void test(const Foo& i) { i.foo(); //fine i.bar(); //error } 

Los valores se pueden asignar, una vez, más tarde en Java, por ejemplo:

 public class Foo { void bar() { final int a; a = 10; } } 

es legal en Java, pero no en C ++, mientras que:

 public class Foo { void bar() { final int a; a = 10; a = 11; // Not legal, even in Java: a has already been assigned a value. } } 

Tanto en Java como en C ++ las variables miembro pueden ser final / const respectivamente. Estos deben tener un valor para el momento en que una instancia de la clase termine de construirse.

En Java deben establecerse antes de que el constructor haya terminado, esto se puede lograr de una de estas dos maneras:

 public class Foo { private final int a; private final int b = 11; public Foo() { a = 10; } } 

En C ++ necesitarás usar listas de inicialización para darles a los miembros de const un valor:

 class Foo { const int a; public: Foo() : a(10) { // Assignment here with = would not be legal } }; 

En Java final se puede usar para marcar cosas como no reemplazables. C ++ (pre-C ++ 11) no hace esto. P.ej:

 public class Bar { public final void foo() { } } public class Error extends Bar { // Error in java, can't override public void foo() { } } 

Pero en C ++:

 class Bar { public: virtual void foo() const { } }; class Error: public Bar { public: // Fine in C++ virtual void foo() const { } }; 

esto está bien, porque la semántica de marcar una función de const es diferente. (También podría sobrecargar al tener solo const en una de las funciones miembro. (Tenga en cuenta también que C ++ 11 permite que las funciones miembro se marquen como definitivas, consulte la sección de actualización C ++ 11)


Actualización de C ++ 11:

C ++ 11 de hecho le permite marcar tanto las clases como las funciones miembro como final , con semántica idéntica a la misma característica en Java, por ejemplo en Java:

 public class Bar { public final void foo() { } } public class Error extends Bar { // Error in java, can't override public void foo() { } } 

Ahora se puede escribir exactamente en C ++ 11 como:

 class Bar { public: virtual void foo() final; }; class Error : public Bar { public: virtual void foo() final; }; 

Tuve que comstackr este ejemplo con un prelanzamiento de G ++ 4.7. Tenga en cuenta que esto no reemplaza a const en este caso, sino que lo aumenta, proporcionando el comportamiento similar a Java que no se vio con la palabra clave C ++ equivalente más cercana. Entonces, si quisieras que una función de miembro fuera final y const , harías:

 class Bar { public: virtual void foo() const final; }; 

(El orden de const y final aquí es obligatorio).

Anteriormente no existía un equivalente directo de las funciones de miembros de la const , aunque la creación de funciones no virtual constituiría una opción potencial, aunque sin causar un error en tiempo de comstackción.

Del mismo modo, el Java:

 public final class Bar { } public class Error extends Bar { } 

se convierte en C ++ 11:

 class Bar final { }; class Error : public Bar { }; 

(Probablemente, constructores private fueron lo más cercano que se podía llegar a esto en C ++)

Curiosamente, para mantener la compatibilidad con versiones anteriores al código C ++ 11, el final no es una palabra clave de la forma habitual. (Tome el trivial y legal C ++ 98 example struct final; para ver por qué convertirlo en una palabra clave rompería el código)

En Java, la palabra clave final se puede usar para cuatro cosas:

  • en una clase o método para sellarlo (no se permiten subclases / anulación)
  • en una variable miembro para declarar que se puede establecer exactamente una vez (creo que esto es de lo que estás hablando)
  • en una variable declarada en un método, para asegurarse de que se puede establecer exactamente una vez
  • en un parámetro de método, para declarar que no se puede modificar dentro del método

Una cosa importante es: ¡una variable de miembro final de Java debe establecerse exactamente una vez! Por ejemplo, en un constructor, statement de campo o inicializador. (Pero no puede establecer una variable miembro final en un método).

Otra consecuencia de hacer que un miembro sea variable final se relaciona con el modelo de memoria, que es importante si trabajas en un entorno enhebrado.

Un objeto const solo puede llamar a métodos const , y generalmente se considera inmutable.

 const Person* person = myself; person = otherPerson; //Valid... unless we declared it const Person* const! person->setAge(20); //Invalid, assuming setAge isn't a const method (it shouldn't be) 

Un objeto final no se puede establecer en un objeto nuevo, pero no es inmutable; no hay nada que impida que alguien llame a ningún método set .

 final Person person = myself; person = otherPerson; //Invalid person.setAge(20); //Valid! 

Java no tiene una forma inherente de declarar objetos inmutables; necesita diseñar la clase como inmutable usted mismo.

Cuando la variable es un tipo primitivo, final / const funcionan de la misma manera.

 const int a = 10; //C++ final int a = 10; //Java a = 11; //Invalid in both languages 

Java final es equivalente a C ++ const en tipos de valores primitivos.

Con los tipos de referencia de Java, la palabra clave final es equivalente a un puntero const … es decir,

 //java final int finalInt = 5; final MyObject finalReference = new MyObject(); //C++ const int constInt = 5; MyObject * const constPointer = new MyObject(); 

Ya tiene algunas respuestas excelentes, pero merece la pena agregar un punto: const en C ++ se usa comúnmente para evitar que otras partes del progtwig cambien el estado de los objetos. Como se ha señalado, el final en Java no puede hacer esto (excepto en el caso de las primitivas), solo evita que la referencia se cambie a un objeto diferente. Pero si está utilizando una Collection , puede evitar cambios en sus objetos utilizando el método estático

  Collection.unmodifiableCollection( myCollection ) 

Esto devuelve una referencia de Collection que proporciona acceso de lectura a los elementos, pero arroja una excepción si se intentan modificaciones, lo que lo hace un poco como const en C ++

Javas final solo funciona en tipos primitivos y referencias, nunca en instancias de objetos donde la palabra clave const funciona en cualquier cosa.

comparar const list melist; con el final List melist; el primero hace que sea imposible modificar la lista, mientras que el último solo le impide asignar una nueva lista a Melist.

¡Además de tener ciertas y sutiles propiedades de subprocesamiento múltiple , las variables declaradas final no necesitan ser inicializadas en la statement!

es decir, esto es válido en Java:

 // declare the variable final int foo; { // do something... // and then initialize the variable foo = ...; } 

Esto no sería válido si se escribe con la const C ++

De acuerdo con wikipedia :

  • En C ++, un campo const no solo está protegido de reasignación, sino que existe la limitación adicional de que solo se pueden invocar los métodos const y solo se puede pasar como el argumento const de otros métodos.
  • Las clases internas no estáticas pueden acceder libremente a cualquier campo de la clase envolvente, final o no.

Supongo que dice “aproximadamente” porque el significado de const en C ++ se complica cuando hablamos de punteros, es decir punteros constantes contra punteros a objetos constantes. Como no hay punteros “explícitos” en Java, final no tiene estos problemas.

Permítanme explicar lo que entendí con un ejemplo de statement de cambio / caso.

Los valores en cada statement de caso deben ser valores constantes de tiempo de comstackción del mismo tipo de datos que el valor de conmutación.

declare algo como a continuación (ya sea en su método como instancias locales, o en su clase como variable estática (luego agregue static a él), o una variable de instancia.

 final String color1 = "Red"; 

y

 static final String color2 = "Green"; switch (myColor) { // myColor is of data type String case color1: //do something here with Red break; case color2: //do something with Green break; } 

Este código no se comstackrá si color1 es una variable de clase / instancia y no una variable local. Esto se comstackrá si color1 se define como estática final (luego se convierte en variable final estática).

Cuando no se comstack, obtendrá el siguiente error

 error: constant string expression required 

la palabra clave “const” significa que su variable se guarda en la ROM (con microprocesador). en la computadora, su variable se guarda en el área de RAM para el código de ensamblaje (solo lectura de RAM). significa que su variable no se encuentra en la memoria RAM que se puede incluir incluyen: memoria estática, memoria de stack y memoria de stack.

la palabra clave “final” significa que su variable se guarda en RAM escribible, pero observará al comstackdor que su variable solo cambia una vez.

 //in java language you can use: static final int i =10; i =11; //error is showed here by compiler //the same in C++ the same as follows int i =10; const int &iFinal = i; iFinal = 11; //error is showed here by compiler the same as above 

Creo que “const” es malo en rendimiento, por lo que Java no lo usa.