2012-01-10 19 views
6

¿Qué sucede cuando una superclase tiene un campo marcado como final, pero una subclase anula (oculta?) Este campo? 'Final' no detiene esto, ¿verdad? El ejemplo específico en el que estoy trabajando es una clase Building, de la que heredan diferentes tipos de edificios. El costo de cada tipo, entre otras cosas, debe ser final para cada subclase, pero cada tipo de edificio debe tener su propio costo.¿Herencia de campos finales en Java?

Editar: Desde entonces me he dado cuenta de que no tenía ni idea de lo que estaba hablando anteriormente. Lo que realmente quiero son variables estáticas de costo. Sin embargo, si declaro estas variables estáticas en la superclase, son estáticas para la superclase, por lo que Subclass1.cost, por ejemplo, se refiere al mismo valor que Superclass.cost o Subclass2.cost. ¿Cómo puedo crear variables que sean estáticas para cada subclase, sin tener que declararlas en cada clase?

+0

Hacer el campo privado. –

+0

Algo así como los cambios de costo de vez en cuando ¿no? Por qué hacerlo final No creo que esconder un campo sea una buena idea. –

Respuesta

11

La palabra clave final, cuando se aplica a campos de una clase Java, no tiene nada que ver con la herencia. En cambio, indica que fuera del constructor, ese campo no puede ser reasignado.

Java trata el nombre que oculta y anula por separado. Anulación realmente cambia el comportamiento observable del programa en el tiempo de ejecución al cambiar a qué función se llama, mientras que ocultar el nombre cambia el programa al cambiar la interpretación estática de qué campo se está haciendo referencia. final tal como se aplica a la anulación solo funciona para los métodos, porque los campos en Java no se pueden anular. El uso de final en estos diferentes contextos es un poco confuso, desafortunadamente, y no hay forma de evitar que un campo tenga su nombre oculto en una subclase.

Si desea que los edificios tengan costos diferentes, una opción sería tener un método getCost reemplazado que se anula de manera diferente en cada clase derivada. Alternativamente, podría tener un solo campo protected o private en la clase base que almacena el costo, luego haga que cada subclase configure este campo directamente (si es protected) o mediante un constructor de clase base (si este campo es private).

Espero que esto ayude!

+0

¿Quiere decir que crea el campo protegido en la superclase, que luego se asigna automáticamente a diferentes valores en el constructor de la subclase? Suena razonable. – TheTedinator

+1

@TheTedinator: esto funcionará si renuncia al modificador 'final' del campo. Si el campo es 'final', no se le pueden asignar valores diferentes en el constructor de la subclase. En cambio, el constructor de la subclase tendría que pasar el valor hasta el constructor de la superclase que se asignará (como mostré en mi respuesta). Si la superclase no asigna un valor en su constructor, el código no se compilará; si el constructor de la subclase intenta establecer el valor de un campo 'final' de una superclase, el código no se compilará. –

+0

@templatetypedef "indica que fuera del constructor, ese campo no se puede reasignar" no es realmente correcto: un campo final no se puede reasignar en absoluto, ni siquiera en el constructor. Debido a eso, un constructor de subclase no puede anular un campo final de la superclase como declaró Ted Hopp. – Sebastian

3

Puede hacerlo de dos maneras: realice una función de acceso y oculte el campo en sí o transfiera el costo de construcción al constructor de la clase superior de la subclase. Se pueden combinar estos y hacer que una propiedad que no puede ser anulado por subclases:

public class Building { 
    private final int cost; 

    protected Building(int cost, ...) { 
     this.cost = cost; 
    } 

    public final int getCost() { 
     return cost; 
    } 
} 

public class Cottage extends Building { 
    public Cottage() { 
     super(COTTAGE_COST, ...); 
    } 
} 
1

de acuerdo con otras respuestas, pero creo que la siguiente aplicación es mejor en este caso:

public abstract class Building { 

     private final int cost; 

     public Building(int cost) { 
      this.cost = cost; 
     } 

     public final int getCost() { 
      return cost; 
     } 
    } 

    class Skyscraper extends Building { 
     public Skyscraper() { 
      super(100500); 
     } 
    } 

Por supuesto, el campo podría ser hecha pública, pero esa es la otra historia ...