2009-04-21 15 views
10

que sigue es una parte de mi código para un proyecto:Tener 2 variables con el mismo nombre en una clase que amplía otra clase en Java

public class Body extends Point{ 
    public double x, y, mass; 

    public Body() { 
     x = y = mass = 0; 
    } 

    public Body(double x, double y, double mass) { 
     this.mass = mass; 
     this.x = x; 
     this.y = y; 
    } 
} 

public class Point { 
    public double x; 
    public double y; 

    public Point(double x, double y) { 
     this.x = x; 
     this.y = y; 
    } 
} 

rápidamente me di cuenta de que haciendo esto creará dos las variables en el interior la clase del cuerpo llamó x y otras dos variables en el cuerpo llamado y. ¿Cómo es esto posible, y por qué demonios lo permite Java?

Asumo que esto es el código correcto del cuerpo de la clase:

public class Body extends Point{ 
    public double mass; 

    public Body() { 
     super(); 
     mass = 0; 
    } 

    public Body(double x, double y, double mass) { 
     super(x,y); 
     this.mass = mass; 
    } 
} 

Gracias por su tiempo

+0

Entonces, si tengo un método con un parámetro Point y envío una instancia de la clase Body, ¿podré acceder a las variables x e y desde Point de esa instancia? Y si tuviera el parámetro de entrada de tipo Body en lugar de Point, ¿solo podría acceder a las variables xey desde Body? –

Respuesta

10

En un sentido, está sustituyendo los campos de la superclase. Pero es mucho más fácil hacerlo accidentalmente porque no hay sobrecarga de campos (solo tienes una variable de un nombre dado, el tipo no importa). Esto se conoce como variable "ocultar" o "sombrear". Entonces, tienes razón, terminarás con dos campos con el mismo nombre.

Su segundo ejemplo es correcto. Se heredan de la superclase y, dado que no se declaran privadas, son visibles para la subclase. En general, es una mala práctica referirse directamente a los campos de una súper clase, y a menos que haya una buena razón, deberían declararse privados. Su ejemplo de invocación del superconstructor es el mejor enfoque.

Además, si oculta un campo con otro del mismo nombre, todavía puede referirse a ellos como super.x, super.y, frente a this.x, this.y, debe evitar esta situación si al todo posible.

+0

Entonces, si tengo un método con un parámetro Point y envío una instancia de la clase Body, ¿podré acceder a las variables x e y desde Point de esa instancia? Y si tuviera el parámetro de entrada de tipo Body en lugar de Point, ¿solo podría acceder a las variables xey desde Body? –

+0

@Martin Andersson sí, dado que Point solo 'sabe' sobre x cualquier y, y su tipo de parámetro determina cómo su código 've' el objeto. Por supuesto, podrías bajar el punto p; Cuerpo b = ((Cuerpo) p); b.mass = xxx; ¡Pero nunca hagas esto! ;-) –

1

Me di cuenta rápidamente de que al hacerlo crearía dos variables dentro de la clase Body llamadas x y otras dos variables en Body llamada y. ¿Cómo es esto posible, y por qué demonios lo permite Java?

En realidad, no, no estás creando dos variables con el mismo nombre, obviamente un compilador no debería y no permitiría esto.

Lo que están haciendo es sombrear las variables existentes definidos como x y y, lo que significa que Body.x y Body.y se solapan esencialmente los nombres para punto.x y Punto.y, por lo que los dos última variable completamente inaccesible de la clase Body (link to Java Language Specification definition of "shadowing").

El sombreado de nombres generalmente se percibe como una mala práctica y una causa de errores, y si aparece las advertencias del compilador javac, el compilador le advertirá diligentemente sobre esto.

+1

En realidad, todavía puede acceder a esas variables, usando Point.this.x y Point.this.y en la clase de cuerpo – Jorn

+1

Ambas variables tienen el mismo nombre. Se acaban de declarar en diferentes clases. Los nombres de las variables son solo "x" e "y", no "Body.x", "Body.y", "Point.x" y "Point.y". Incluso el enlace que dio sobre el sombreado dice: "Algunas declaraciones pueden ser sombreadas en parte de su alcance por otra declaración del mismo nombre [...]" - observe la parte del "mismo nombre". –

+0

J.S .: Creo que M.B. pretendía ser código descriptivo en lugar de ejecutable. –

5

Sí, tendrá dos variables, una de ellas ocultando la otra. Tiene sentido para permitir que por dos razones:

  1. Supongamos que tienes una clase base Base y una clase derivada Derived que el autor de Base tiene ni idea. ¿El autor de Base nunca puede agregar ningún campo, simplemente porque una clase derivada podría compartir los campos? ¿O debería Derived dejar de compilar cuando el cambio a Base en realidad no afecta la corrección?
  2. Sus campos casi siempre deben ser privados, en cuyo caso no importa si los nombres están duplicados o no, ni "lado" conocerá las variables de la otra.
4

Además de lo que otros han dicho: ¿Es Body a Point? No, Body tiene una posición propiedad del tipo Point. Por lo tanto, Body probablemente no debería extender Point. Si se deshace de la herencia (de la implementación), entonces se deshace de muchos problemas. Eso y usa private (no protected!) Y final generosamente.

+0

Si bien en general, "preferir la composición sobre la herencia" es bueno, también es posible que el diseñador quiera que Body tenga todas las propiedades de Point (presumiblemente hay otras que se han omitido para mayor claridad). – DJClayworth

Cuestiones relacionadas