2012-01-27 16 views
11

Mi clase Parent es:herencia, firma del método, el método de primer orden y cláusula throws

import java.io.IOException; 
public class Parent { 
     int x = 0; 
     public int getX() throws IOException{ 
     if(x<=0){ 
     throw new IOException(); 
     } 
     return x; 
     } 
} 

I extend esta clase para escribir una subclase Child:

public class Child1 extends Parent{ 
    public int getX(){ 
     return x+10; 
    } 
} 

Aviso mientras anulando la getX método en la clase Child, he eliminado la cláusula throws de la definición del método. Ahora da como resultado un comportamiento anómalo por el compilador que se espera:

new Parent().getX() ; 

no compila sin formar parte de un bloque try-catch, como se esperaba.

new Child().getX() ; 

compila sin formar parte de un bloque try-catch.

Pero las siguientes líneas de código necesitan el bloque try-catch.

Parent p = new Child(); 
p.getX(); 

Como esto se podía prever es decir, utilizando una referencia de la clase padre para invocar un método hijo durante el polimorfismo en tiempo de ejecución, por qué los diseñadores de Java no hacen obligatoria la inclusión de la cláusula throws en el método de definición, mientras anulando un método particular de clase padre? Quiero decir, si un método de clase padre tiene la cláusula throws en su definición, entonces, al anularlo, el método de anulación también debería incluir la cláusula throws, ¿no es así?

+0

En su última frase, hizo que quiere decir "a continuación, mientras se sobreescriben que la *** *** primordial método (el método en la subclase) también debe incluir la cláusula throws" ??? – Bhushan

Respuesta

25

No, esto es apropiado - un método reemplazado puede ser más restrictiva en lo que lanza (y retornos), ya que esto puede ser útil para las personas que llaman que conocen en tiempo de compilación que se va a utilizar el método reemplazado, y no quiero molestarme con excepciones que no pueden suceder, etc. Tiene que ser más restrictivo que permisivo, por lo que no puede sorprender a los llamadores que hacen acceder a él a través de la declaración padre.

El uso del método reemplazado a través de una referencia del tipo Parent nunca va a violar el contrato de "podría arrojar IOException" - la ausencia de una excepción no infringe el contrato. A la inversa (si el padre no hizo declara la excepción, pero el método de anulación sí lo hace) sería una violación del contrato.

+0

Gracias por iluminarme :) – NINCOMPOOP

+0

puedes aceptar la respuesta de Jon :) – Bhushan

+0

'para que no sorprenda a las personas que llaman que sí acceden a ella a través de la declaración de los padres'. Esto realmente me ayudó a entender el razonamiento. –

3

Bueno, el método primordial podría no arrojar ninguna excepción (o al menos menos excepciones), por lo que puede eliminar excepciones de la cláusula throw (o la cláusula throw en su conjunto).

Supongamos que el método de anulación detecta todas las excepciones, las registra y devuelve un valor especial. Aunque no es un buen estilo (cambiaría la semántica del método) aún es posible y, por lo tanto, no tendría que atrapar excepciones que nunca se lanzan si sabe en tiempo de compilación que está tratando con un Child.

La adición de excepciones no funcionará, ya que los usuarios de la clase que acceden a ella a través de la referencia Parent no conocen ninguna excepción que Child pueda agregar.

2

Tiene la libertad de anular un método sin la palabra clave throws, porque si desea desarrollar un método controlando todas las excepciones, puede hacerlo anulando el método sin cláusula throws.

Pero recuerde una cosa: si desea incluir la cláusula throws en el método de la subclase, la cláusula throws debe asociarse con la excepción que debe ser la misma o la subclase de la excepción que arroja su método de superclase. por ejemplo-

class Super{ 
    void a()throws IOException{ 
     ...... 
    } 
} 
class Sub extends Super{ 
    void a()throws IOException{ 
     ...... 
    } 
} 

La una() de la clase Sub debe lanzar IOException o cualquier subclase de IOException, de lo contrario el compilador mostrará error.

Eso significa que si usted escribe

void a()throws Exception 

en el Sub clase, entonces causará error de compilación.

2

fácil de recordar

  1. modificador de acceso se puede cambiar desde restringido a menos restringida,
    por ejemplo, de proteger al público, pero no viceversa
  2. tiros firma puede haber cambios de excepción padres a hijos clase de excepción, pero no viceversa

Este código es válido

public class A { 

    protected String foo() throws Exception{ 
     return "a"; 
    } 

    class B extends A { 
     @Override 
     public String foo() throws IOException{ 
      return "b"; 
     } 
    } 
} 

método foo overrided tiene acceso público, no protegido y lanza IOException ese niño de Excepción

Este código no es válido

public class A { 

    public String foo() throws IOException{ 
     return "a"; 
    } 

    class B extends A { 
     @Override 
     protected String foo() throws Exception{ 
      return "b"; 
     } 
    } 
} 

método foo overrided tiene modificador de acceso más restringido y lanza excepción que no niño de IOException

Por el camino se puede reemplazar el método de la superclase y no tirar ecxeptions en absoluto

Esta c oda válida

public class A { 

    public String foo() throws IOException{ 
     return "a"; 
    } 

    class B extends A { 
     @Override 
     public String foo(){ 
      return "b"; 
     } 
    } 
} 
+0

Esto ayuda, se destruyó en la entrevista debido a esta pregunta. – saiki4116

Cuestiones relacionadas