2010-09-25 9 views
6

Esta es otra de esas preguntas SCJP. El siguiente código imprime Alpha:fooBeta:fooBeta:barBeta:bar, y no entiendo por qué la primera llamada de foo eligió Alpha's foo en lugar de Beta's. Si el parámetro Alpha.foo se cambia a String en lugar de String ..., la salida es Beta:fooBeta:fooBeta:barBeta:bar, lo que tiene sentido.¿Cómo se eligió un método sobre otro en este código?

Según tengo entendido, cuando dice Alpha a = new Beta();, el compilador busca Alpha.foo, pero la JVM realmente ejecutará Beta.foo. Por un lado, Beta tiene un método foo cuya firma coincide con la llamada. Por otro lado, pensé que los métodos varargs solo se ejecutan cuando no hay otro método disponible que coincida con la llamada. Así que esas son dos razones por las que creo que Alpha.foo no debería ejecutarse. ¿Qué parte de esta comprensión es incorrecta?

Gracias!

class Alpha { 

    public void foo(String... args) { //if this were String args, then it makes sense 
     System.out.print("Alpha:foo"); 
    } 

    public void bar(String a) { 
     System.out.print("Alpha:bar"); 
    } } 

public class Beta extends Alpha { 

    public void foo(String a) { 
     System.out.print("Beta:foo"); 
    } 

    public void bar(String a) { 
     System.out.print("Beta:bar"); 
    } 

    public static void main(String[] arg) { 
     Alpha a = new Beta(); 
     Beta b = (Beta) a; 
     a.foo("test");//confusing line 
     b.foo("test"); 
     a.bar("test"); 
     b.bar("test"); 
    } } 

Editar: Creo que sé dónde he malinterpretado las cosas ahora. Pensé que en una situación SuperClass sc = new SubClass();, cualquier método que se solicite en sc se buscará en SubClass en tiempo de ejecución, aunque se buscará en SuperClass en tiempo de compilación. Resulta que, como ahora creo entender, cualquier método que se solicite sc se buscará en SuperClass en tiempo de compilación y tiempo de ejecución, A MENOS QUE SubClass haya proporcionado una versión "mejor" del método. Luego, incluso en tiempo de compilación, el compilador sabrá que el método para invocar es la versión SubClass.

Respuesta

4

método se realiza en tiempo de compilación, método anulando - en tiempo de ejecución.

En su caso, el foo en Beta no anula foo en Alpha. Lo sobrecarga con diferentes argumentos (Puede probar esto agregando la anotación @Override, que es una práctica recomendada para detectar problemas potenciales no tan obvios).

Otra cosa escurridiza aquí es que no puede invocar Alpha#foo(..) desde una referencia de Beta - es decir, b.foo("test") siempre invocará el método no varargs. Como de por qué sucede esto, ver this question

6

Un método con un parámetro String[] o String... y un método con un parámetro String no comparten la misma firma. Una matriz de cadenas es un tipo completamente separado, por lo que es una sobrecarga estándar y no se está produciendo polimorfismo. El compilador ve que es una instancia del tipo "Alpha" e invoca el método foo que se encuentra allí. El método foo en Beta no se llama porque no es en realidad una anulación de la versión Alpha.

(aquí es donde el @Override anotación viene muy bien. Si se trató de usarlo en la versión beta de foo, se obtendría un error de compilación.) Sobrecarga

2

Desde A y B "foo()" métodos no tiene la misma firma, b método "foo()" hace no override un "foo()" método.

Por esa razón, cuando llamas "a.foo()", Alpha.foo().

Para verificar eso, puede intentar colocar una anotación "@Override" en el método "b.foo()". Esto dará como resultado un error de compilación (ya que "b.foo()" no anula nada).

2

Cuando dice Super a = new Sub(); y hacer a.methodCall(); se aplica la siguiente regla ...

Vea si la subclase tiene un método que anula el método en superclase y lo llama.

Pero este método en subclase no anula, sino que sobrecarga el método en super, por lo que se llama a una implementación de superclase. Cuando haces argumentos a los dos métodos iguales. Entonces se aplica el principio primordial.

0

Anulación se produce en tiempo de ejecución, aquí en el caso de que no prevalezcan foo método como parámetros de métodos de superclase y subclase son different.A método con un parámetro String[] or String... y un método con un parámetro de cadena no son iguales.

Cuestiones relacionadas