En Java usamos final
palabras clave con variables para especificar que sus valores no se deben cambiar. Pero veo que puedes cambiar el valor en el constructor / métodos de la clase. Nuevamente, si la variable es, static
entonces es un error de compilación.
Aquí está el código:
import java.util.ArrayList;
import java.util.List;
class Test {
private final List foo;
public Test()
{
foo = new ArrayList();
foo.add("foo"); // Modification-1
}
public static void main(String[] args)
{
Test t = new Test();
t.foo.add("bar"); // Modification-2
System.out.println("print - " + t.foo);
}
}
El código anterior funciona bien y sin errores.
Ahora cambie la variable como static
:
private static final List foo;
Ahora es un error de compilación. ¿Cómo funciona esto final
realmente?
Respuestas:
Siempre se le permite inicializar una
final
variable. El compilador se asegura de que pueda hacerlo solo una vez.Tenga en cuenta que los métodos de llamada en un objeto almacenado en una
final
variable no tienen nada que ver con la semántica definal
. En otras palabras: sefinal
trata solo de la referencia en sí, y no del contenido del objeto referenciado.Java no tiene concepto de inmutabilidad de objeto; Esto se logra diseñando cuidadosamente el objeto, y es un esfuerzo lejos de ser trivial.
fuente
final
. Los objetos mutables también se pueden asignar en pila.final
Sin embargo, los campos pueden ayudar al análisis de escape, pero esa es una ruta bastante indirecta. También tenga en cuenta que efectivamente las variables finales tienen un tratamiento idéntico al marcadofinal
en el código fuente.final
está presente en el archivo de clase y tiene consecuencias semánticas significativas para optimizar el tiempo de ejecución. También puede incurrir en costos porque el JLS tiene una fuerte garantía sobre la consistencia de losfinal
campos de un objeto. Por ejemplo, el procesador ARM debe usar una instrucción de barrera de memoria explícita al final de cada constructor de una clase que tengafinal
campos. Sin embargo, en otros procesadores esto no es necesario.Esta es una pregunta de entrevista favorita . Con estas preguntas, el entrevistador trata de averiguar qué tan bien comprende el comportamiento de los objetos con respecto a los constructores, métodos, variables de clase (variables estáticas) y variables de instancia.
En el caso anterior, hemos definido un constructor para 'Test' y le hemos dado un método 'setFoo'.
Acerca del constructor: el constructor se puede invocar solo una vez por creación de objeto utilizando la
new
palabra clave. No puede invocar al constructor varias veces, porque el constructor no está diseñado para hacerlo.Acerca del método: se puede invocar un método tantas veces como desee (incluso nunca) y el compilador lo sabe.
escenario 1
foo
es una variable de instancia Cuando creamosTest
un objeto de clase, la variable de instanciafoo
se copiará dentro del objeto deTest
clase. Si asignamosfoo
dentro del constructor, entonces el compilador sabe que el constructor se invocará solo una vez, por lo que no hay problema para asignarlo dentro del constructor.Si asignamos
foo
dentro de un método, el compilador sabe que un método puede llamarse varias veces, lo que significa que el valor tendrá que cambiarse varias veces, lo que no está permitido para unafinal
variable. ¡Entonces el compilador decide que el constructor es una buena opción! Puede asignar un valor a una variable final solo una vez.Escenario 2
foo
ahora es una variable estática . Cuando creamos una instancia deTest
clase,foo
no se copiará al objeto porquefoo
es estático. Ahorafoo
no es una propiedad independiente de cada objeto. Esta es una propiedad deTest
clase. Perofoo
pueden ser vistos por varios objetos y si cada objeto que se crea utilizando lanew
palabra clave invocará finalmente alTest
constructor que cambia el valor en el momento de la creación de múltiples objetos (Rememberstatic foo
no se copia en cada objeto, sino que se comparte entre varios objetos) .)Escenario 3
Arriba
Modification-2
es de su pregunta. En el caso anterior, no está cambiando el primer objeto al que se hace referencia, pero está agregando contenido dentro delfoo
cual está permitido. El compilador se queja si intenta asignar unnew ArrayList()
a lafoo
variable de referencia.Regla Si ha inicializado una
final
variable, no puede cambiarla para referirse a un objeto diferente. (En este casoArrayList
)las clases finales no pueden subclasificarse, los métodos
finales no pueden anularse. (Este método está en la superclase) los métodos
finales pueden anularse. (Lea esto en forma gramatical. Este método está en una subclase)
fuente
foo
se establecería varias veces a pesar de la designación final sifoo
se establece en la clase Prueba y se crean múltiples instancias de Prueba?foo
puede ser ... múltiples objetos). ¿ Eso significa que si creo múltiples objetos a la vez, entonces qué objeto está inicializando la variable final depende de la ejecución?final
a la dirección de memoria a la que hace referenciafoo
una ArrayList. No está asignandofinal
a la dirección de memoria referenciada por el primer elemento defoo
(o cualquier elemento para el caso). Por lo tanto no puedes cambiarfoo
pero puedes cambiarfoo[0]
.foo = new ArrayList();
-foo
se refiere a la variable estática porque estamos dentro de la misma clase.final
en una variable como lo mismo que laconst
palabra clave en C ++?La palabra clave final tiene numerosas formas de uso:
Otro uso:
Una variable de clase estática existirá desde el inicio de la JVM, y debe inicializarse en la clase. El mensaje de error no aparecerá si haces esto.
fuente
static
campos (siempre que no lo seanfinal
) tantas veces como desee. Vea este wiki para conocer la diferencia entre asignación e inicialización .La
final
palabra clave se puede interpretar de dos maneras diferentes dependiendo de para qué se utiliza:Tipos de valor: para
int
s, s,double
etc., garantizará que el valor no pueda cambiar,Tipos de referencia: para referencias a objetos,
final
asegura que la referencia nunca cambiará, lo que significa que siempre se referirá al mismo objeto. No garantiza en absoluto que los valores dentro del objeto sean referidos para permanecer igual.Como tal,
final List<Whatever> foo;
asegura quefoo
siempre se refiere a la misma lista, pero el contenido de dicha lista puede cambiar con el tiempo.fuente
Si hace
foo
estática, debe inicializarla en el constructor de la clase (o en línea donde la defina) como en los siguientes ejemplos.Constructor de clase (no instancia):
En línea:
El problema aquí no es cómo funciona el
final
modificador, sino cómo funciona elstatic
modificador.El
final
modificador impone una inicialización de su referencia para cuando finalice la llamada a su constructor (es decir, debe inicializarlo en el constructor).Cuando inicializa un atributo en línea, se inicializa antes de que se ejecute el código que ha definido para el constructor, por lo que obtiene los siguientes resultados:
foo
esstatic
,foo = new ArrayList()
se ejecutará antes de que se ejecute elstatic{}
constructor que ha definido para su clasefoo
no es asístatic
,foo = new ArrayList()
se ejecutará antes de ejecutar su constructorCuando no inicializa un atributo en línea, el
final
modificador exige que lo inicialice y que debe hacerlo en el constructor. Si también tiene unstatic
modificador, el constructor tendrá que inicializar el atributo es el bloque de inicialización de clase:static{}
.El error que obtiene en su código se debe al hecho de que
static{}
se ejecuta cuando se carga la clase, antes del momento en que crea una instancia de un objeto de esa clase. Por lo tanto, no habrá inicializadofoo
cuando se crea la clase.Piense en el
static{}
bloque como un constructor de un objeto de tipoClass
. Aquí es donde debe hacer la inicialización de losstatic final
atributos de su clase (si no se hace en línea).Nota al margen:
El
final
modificador asegura la constancia solo para tipos primitivos y referencias.Cuando declaras un
final
objeto, lo que obtienes es unafinal
referencia a ese objeto, pero el objeto en sí no es constante.Lo que realmente está logrando al declarar un
final
atributo es que, una vez que declara un objeto para su propósito específico (como elfinal List
que ha declarado), eso y solo ese objeto se usará para ese propósito: no podrá cambiarList foo
a otroList
, pero aún puede alterarloList
agregando / eliminando elementos (elList
que esté usando será el mismo, solo con su contenido alterado).fuente
Esta es una muy buena pregunta de entrevista. A veces incluso pueden preguntarte cuál es la diferencia entre un objeto final y un objeto inmutable.
1) Cuando alguien menciona un objeto final, significa que la referencia no se puede cambiar, pero su estado (variables de instancia) se puede cambiar.
2) Un objeto inmutable es aquel cuyo estado no se puede cambiar, pero se puede cambiar su referencia. Ex:
La variable de referencia x se puede cambiar para señalar una cadena diferente, pero el valor de "abc" no se puede cambiar.
3) Las variables de instancia (campos no estáticos) se inicializan cuando se llama a un constructor. Entonces puede inicializar valores a sus variables dentro de un constructor.
4) "Pero veo que puedes cambiar el valor en el constructor / métodos de la clase". - No se puede cambiar dentro de un método.
5) Una variable estática se inicializa durante la carga de clases. Por lo tanto, no se puede inicializar dentro de un constructor, se debe hacer incluso antes. Por lo tanto, debe asignar valores a una variable estática durante la declaración misma.
fuente
La
final
palabra clave en java se usa para restringir al usuario. Lafinal
palabra clave java se puede usar en muchos contextos. Final puede ser:La
final
palabra clave se puede aplicar con las variables, unafinal
variable que no tiene valor, se llamafinal
variable en blanco ofinal
variable no inicializada . Se puede inicializar solo en el constructor. Lafinal
variable en blanco puede serstatic
también la que se inicializará solo en elstatic
bloque.Variable final de Java:
Si realiza alguna variable como
final
, no puede cambiar el valor de lafinal
variable (será constante).Ejemplo de
final
variableHay un límite de velocidad de la variable final, vamos a cambiar el valor de esta variable, pero no se puede cambiar porque la variable final una vez asignado un valor nunca se puede cambiar.
Clase final de Java:
Si haces alguna clase como
final
, no puedes extenderla .Ejemplo de clase final
Método final de Java:
Si realiza algún método como final, no puede anularlo .
Ejemplo de
final
método (run () en Honda no puede anular run () en Bike)compartido desde: http://www.javatpoint.com/final-keyword
fuente
Vale la pena mencionar algunas definiciones sencillas:
Clases / Métodos
Variables
final
básicamente, evitar sobrescribir / sobrescribir por cualquier cosa (subclases, variable "reasignar"), según el caso.fuente
final
es una palabra clave reservada en Java para restringir al usuario y se puede aplicar a variables miembro, métodos, clases y variables locales. Las variables finales a menudo se declaran con lastatic
palabra clave en Java y se tratan como constantes. Por ejemplo:Cuando usamos la
final
palabra clave con una declaración de variable, el valor almacenado dentro de esa variable no se puede cambiar más tarde.Por ejemplo:
Nota : Una clase declarada como final no se puede extender o heredar (es decir, no puede haber una subclase de la superclase). También es bueno tener en cuenta que los métodos declarados como finales no pueden ser anulados por subclases.
Los beneficios de usar la palabra clave final se abordan en este hilo .
fuente
the value stored inside that variable cannot be changed latter
Es parcialmente cierto. Es cierto solo para tipos de datos primitivos. En caso de que algún objeto se haga comofinal
, como la lista de arrays, su valor puede cambiar pero no la referencia. ¡Gracias!Supongamos que tiene dos huchas, rojo y blanco. Usted asigna estas cajas de dinero solo a dos hijos y no se les permite intercambiar sus cajas. Entonces, tienes huchas rojas o blancas (final), no puedes modificar la caja pero puedes poner dinero en tu caja. A nadie le importa (Modificación-2).
fuente
Lee todas las respuestas.
Hay otro caso de usuario donde
final
se puede usar la palabra clave, es decir, en un argumento de método:Se puede usar para variables que no se deben cambiar.
fuente
Cuando lo hace estático final, debe inicializarse en un bloque de inicialización estático
fuente
La
final
palabra clave indica que una variable solo puede inicializarse una vez. En su código, solo está realizando una inicialización de final para que se cumplan los términos. Esta declaración realiza la inicialización solitaria defoo
. Tenga en cuenta quefinal
! = Inmutable, solo significa que la referencia no puede cambiar.Cuando declara
foo
questatic final
la variable debe inicializarse cuando se carga la clase y no puede confiar en la instanciación (también llamada llamada al constructor) para inicializarfoo
ya que los campos estáticos deben estar disponibles sin una instancia de una clase. No hay garantía de que se haya llamado al constructor antes de usar el campo estático.Cuando ejecuta su método en el
static final
escenario, laTest
clase se carga antes de instanciart
en este momento, no hay instanciación defoo
significado, no se ha inicializado, por lo quefoo
se establece en el valor predeterminado para todos los objetos que esnull
. En este punto, supongo que su código arroja unNullPointerException
cuando intenta agregar un elemento a la lista.fuente
En primer lugar, el lugar en su código donde está inicializando (es decir, asignando por primera vez) foo está aquí:
foo es un objeto (con tipo Lista), por lo que es un tipo de referencia , no un tipo de valor (como int). Como tal, contiene una referencia a una ubicación de memoria (por ejemplo, 0xA7D2A834) donde se almacenan los elementos de la Lista. Líneas como esta
no cambie el valor de foo (que, de nuevo, es solo una referencia a una ubicación de memoria). En cambio, simplemente agregan elementos en esa ubicación de memoria referenciada. Para violar la palabra clave final , debería intentar reasignar foo de la siguiente manera:
Eso te daría un error de compilación.
Ahora, con eso fuera del camino, piense en lo que sucede cuando agrega la palabra clave estática .
Cuando NO tiene la palabra clave estática, cada objeto que crea una instancia de la clase tiene su propia copia de foo. Por lo tanto, el constructor asigna un valor a una copia nueva en blanco de la variable foo, que está perfectamente bien.
Sin embargo, cuando TIENES la palabra clave estática, solo existe un foo en la memoria que está asociado con la clase. Si fuera a crear dos o más objetos, el constructor intentaría reasignar ese foo cada vez, violando la palabra clave final .
fuente
final
solo une la referencia a un objeto en particular. Usted es libre de cambiar el "estado" de ese objeto, pero no el objeto en sí.fuente
Los siguientes son contextos diferentes donde se usa final.
Variables finales Una variable final solo se puede asignar una vez. Si la variable es una referencia, esto significa que la variable no se puede volver a vincular para hacer referencia a otro objeto.
A la variable final se le puede asignar un valor más tarde (no es obligatorio asignarle un valor cuando se declara), pero solo una vez.
Clases finales Una clase final no se puede extender (heredar)
Métodos finales Las subclases no pueden anular un método final.
fuente
Pensé en escribir una respuesta actualizada y en profundidad aquí.
final
La palabra clave se puede utilizar en varios lugares.A
final class
significa que ninguna otra clase puede extender esa clase final. Cuando Java Run Time ( JRE ) sabe que una referencia de objeto está en el tipo de una clase final (digamos F), sabe que el valor de esa referencia solo puede estar en el tipo de F.Ex:
Entonces, cuando ejecuta cualquier método de ese objeto, ese método no necesita ser resuelto en tiempo de ejecución usando una tabla virtual . es decir, el polimorfismo en tiempo de ejecución no se puede aplicar. Entonces el tiempo de ejecución no se preocupa por eso. Lo que significa que ahorra tiempo de procesamiento, lo que mejorará el rendimiento.
A
final method
de cualquier clase significa que cualquier clase secundaria que extienda esa clase no puede anular ese método o métodos finales. Por lo tanto, el comportamiento del tiempo de ejecución en este escenario también es bastante similar al comportamiento anterior que mencioné para las clases.Si se especificó algún tipo de arriba como
final
, significa que el valor ya está finalizado, por lo que el valor no se puede cambiar .Ex:
Para campos, parámetros locales
Para parámetros del método
Esto simplemente significa que el valor del valor de
final
referencia no se puede cambiar. es decir, solo se permite una inicialización. En este escenario, en tiempo de ejecución, dado que JRE sabe que los valores no se pueden cambiar, carga todos estos valores finalizados (de referencias finales) en la caché L1 . Debido a que no es necesario para cargar la espalda y otra vez de la memoria principal . De lo contrario, se carga en el caché L2 y se carga de vez en cuando desde la memoria principal. Por lo tanto, también es una mejora del rendimiento.Entonces, en los 3 escenarios anteriores, cuando no hemos especificado la
final
palabra clave en lugares que podemos usar, no debemos preocuparnos, las optimizaciones del compilador lo harán por nosotros. También hay muchas otras cosas que las optimizaciones del compilador hacen por nosotros. :)fuente
Sobre todo son correctos. Además, si no desea que otros creen subclases de su clase, declare su clase como final. Luego se convierte en el nivel de la hoja de la jerarquía del árbol de clases que nadie puede extender más. Es una buena práctica evitar una gran jerarquía de clases.
fuente