usar sirve simple resueltos que puede para metodo llamar herencia ejercicios donde cuando como comando clase java exception mocking try-catch

java - sirve - ¿cuando se puede usar el constructor super()?



¿Por qué no puedo usar un bloque de prueba alrededor de mi llamada super()? (7)

Desafortunadamente, los compiladores no pueden trabajar sobre principios teóricos, y aunque usted sepa que es seguro en su caso, si lo permitieran, debería ser seguro para todos los casos.

En otras palabras, el compilador no solo lo detiene a usted, sino que detiene a todos, incluso a todos aquellos que no saben que no es seguro y que necesita un manejo especial. Probablemente haya otras razones para esto también, ya que todos los idiomas generalmente tienen formas de hacer cosas inseguras si uno sabe cómo manejarlas.

En C # .NET hay disposiciones similares, y la única forma de declarar un constructor que llama a un constructor base es esta:

public ClassName(...) : base(...)

al hacerlo, se llamará al constructor base antes del cuerpo del constructor, y no puede cambiar este orden.

Entonces, en Java, la primera línea de su constructor TIENE que ser una llamada a super ... ya sea implícitamente llamando a super () o llamando explícitamente a otro constructor. Lo que quiero saber es, ¿por qué no puedo poner un bloque de prueba alrededor de eso?

Mi caso específico es que tengo una clase simulada para una prueba. No hay un constructor predeterminado, pero quiero uno que simplifique la lectura de las pruebas. También quiero ajustar las excepciones lanzadas desde el constructor a una RuntimeException.

Entonces, lo que quiero hacer es efectivamente esto:

public class MyClassMock extends MyClass { public MyClassMock() { try { super(0); } catch (Exception e) { throw new RuntimeException(e); } } // Mocked methods }

Pero Java se queja de que super no es la primera declaración.

Mi solución:

public class MyClassMock extends MyClass { public static MyClassMock construct() { try { return new MyClassMock(); } catch (Exception e) { throw new RuntimeException(e); } } public MyClassMock() throws Exception { super(0); } // Mocked methods }

¿Es esta la mejor solución? ¿Por qué Java no me deja hacer lo primero?

Mi mejor conjetura en cuanto al "por qué" es que Java no quiere dejarme tener un objeto construido en un estado potencialmente inconsistente ... sin embargo, al hacer un simulacro, no me importa eso. Parece que debería ser capaz de hacer lo anterior ... o al menos sé que lo anterior es seguro para mi caso ... o parece que debería ser de todos modos.

Estoy anulando cualquier método que use de la clase probada, por lo que no hay riesgo de que esté usando variables no inicializadas.


No puedo suponer que tengo una comprensión profunda de las partes internas de Java, pero tengo entendido que, cuando un compilador necesita instanciar una clase derivada, primero debe crear la base (y su base antes de eso (...)) y luego abofetear las extensiones hechas en la subclase.

Entonces, ni siquiera es el peligro de las variables no iniciadas ni nada de eso en absoluto. Cuando intenta hacer algo en el constructor de la subclase ''constructor antes de la clase base'', básicamente le está pidiendo al compilador que extienda una instancia de objeto base que todavía no existe.

Editar: en su caso, MyClass se convierte en el objeto base, y MyClassMock es una subclase.


Está hecho para evitar que alguien cree un nuevo objeto SecurityManager partir de un código que no sea de confianza.

public class Evil : SecurityManager { Evil() { try { super(); } catch { Throwable t } { } } }


No sé cómo se implementa Java internamente, pero si el constructor de la superclase arroja una excepción, entonces no hay una instancia de la clase que extienda. Sería imposible llamar a los métodos toString() o equals() , por ejemplo, ya que se heredan en la mayoría de los casos.

Java puede permitir un try / catch alrededor de la llamada a super () en el constructor si 1. anulas TODOS los métodos de las superclases, y 2. no usas la cláusula super.XXX (), pero eso suena demasiado complicado para yo.


Una forma de evitarlo es llamando a una función estática privada. El try-catch se puede colocar en el cuerpo de la función.

public class Test { public Test() { this(Test.getObjectThatMightThrowException()); } public Test(Object o) { //... } private static final Object getObjectThatMightThrowException() { try { return new ObjectThatMightThrowAnException(); } catch(RuntimeException rtx) { throw new RuntimeException("It threw an exception!!!", rtx); } } }


Sé que esta es una vieja pregunta, pero me gustó y, como tal, decidí darle una respuesta. Quizás mi comprensión de por qué esto no se puede hacer contribuirá a la discusión y a los futuros lectores de su interesante pregunta.

Permítanme comenzar con un ejemplo de construcción de objetos fallidos.

Definamos una clase A, tal que:

class A { private String a = "A"; public A() throws Exception { throw new Exception(); } }

Ahora, supongamos que nos gustaría crear un objeto de tipo A en un try...catch block.

A a = null; try{ a = new A(); }catch(Exception e) { //... } System.out.println(a);

Evidentemente, el resultado de este código será: null .

¿Por qué Java no devuelve una versión parcialmente construida de A ? Después de todo, cuando el constructor falla, el campo de name del objeto ya se ha inicializado, ¿no?

Bueno, Java no puede devolver una versión parcialmente construida de A porque el objeto no se construyó correctamente. El objeto está en un estado incoherente y, por lo tanto, Java lo descarta. Su variable A ni siquiera está inicializada, se mantiene como nula.

Ahora, como ya sabe, para construir completamente un objeto nuevo, todas sus superclases deben inicializarse primero. Si una de las super clases no se pudo ejecutar, ¿cuál sería el estado final del objeto? Es imposible determinar eso.

Mira este ejemplo más elaborado

class A { private final int a; public A() throws Exception { a = 10; } } class B extends A { private final int b; public B() throws Exception { methodThatThrowsException(); b = 20; } } class C extends B { public C() throws Exception { super(); } }

Cuando se invoca el constructor de C , si se produce una excepción al inicializar B , ¿cuál sería el valor de la variable int final b ?

Como tal, el objeto C no puede ser creado, es falso, es basura, no está completamente inicializado.

Para mí, esto explica por qué tu código es ilegal.


Sé que esta pregunta tiene numerosas respuestas, pero me gustaría dar mi pequeño chisme sobre por qué esto no estaría permitido, específicamente para responder por qué Java no te permite hacer esto. Así que aquí tienes ...

Ahora, tenga en cuenta que debe llamarse a super() antes que a cualquier otra cosa en el constructor de una subclase, por lo tanto, si utilizó try y catch blocks alrededor de su llamada a super() , los bloques deberían verse así:

try { super(); ... } catch (Exception e) { super(); //This line will throw the same error... ... }

Si super () fails in the block, it HAS to be executed first in the try block, it HAS to be executed first in the block, so that catch block, so that super se runs before anything in your subclass constructor de runs before anything in your subclass . Esto te deja con el mismo problema que tenías al principio: si se lanza una excepción, no se detecta. (En este caso, simplemente se vuelve a lanzar en el bloque catch).

Ahora, el código anterior tampoco está permitido por Java. Este código puede ejecutar la mitad de la primera súper llamada y luego volver a llamar, lo que podría causar algunos problemas con algunas súper clases.

Ahora, la razón por la que Java no permite arrojar una excepción en lugar de llamar a super() es porque la excepción podría capturarse en otro lugar, y el programa continuaría sin llamar a super() en su objeto de subclase, y posiblemente porque la excepción podría tomar su objeto como parámetro e intentar cambiar el valor de las variables de instancia heredadas, que aún no se hubieran inicializado.