Как зайти в Даркнет?!
25th January, 01:11
4
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
893
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
948
0
Очень долго работает Update запрос Oracle
27th January, 09:58
912
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
905
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
938
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1724
0
период по дням
25th October, 10:44
3955
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3720
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4613
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4380
0
Помогите пожалуйста решить задачи
24th November, 23:53
6084
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4350
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4395
0
Метода Крамера С++
23rd October, 11:55
4308
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2598
0
Почему я не могу использовать блок try вокруг моего вызова super()?
Итак, в Java первая строка вашего конструктора HAS должна быть вызовом super... будь то неявный вызов super() или явный вызов другого конструктора. Вот что я хочу знать: почему я не могу поставить пробный блок вокруг этого?
Мой конкретный случай заключается в том, что у меня есть макет класса для теста. Конструктора по умолчанию нет, но я хочу, чтобы он упрощал чтение тестов. Я также хочу обернуть исключения, вызванные из конструктора, в RuntimeException.
Итак, то, что я хочу сделать, это эффективно:
public class MyClassMock extends MyClass {
public MyClassMock() {
try {
super(0);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// Mocked methods
}
Но Java жалуется, что супер-это не первое утверждение.
Мой обходной путь:
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
}
Является ли это лучшим обходным путем? Почему Java не позволяет мне сделать первое?
Моя лучшая догадка относительно "why" заключается в том, что Java не хочет, чтобы я имел сконструированный объект в потенциально противоречивом состоянии... однако, делая глумление, я не забочусь об этом. Кажется, я должен быть в состоянии сделать это выше... или, по крайней мере, я знаю, что вышесказанное безопасно для моего случая... или кажется, что так и должно быть в любом случае.
Я переопределяю все методы, которые я использую из тестируемого класса, поэтому нет никакого риска, что я использую неинициализированные переменные.
К сожалению, компиляторы не могут работать на теоретических принципах, и хотя вы можете знать, что это безопасно в вашем случае, если бы они это позволили, это должно было бы быть безопасно для всех случаев.
Другими словами, компилятор останавливает не только вас, он останавливает всех, включая всех тех, кто не знает, что он небезопасен и нуждается в специальной обработке. Вероятно, есть и другие причины для этого, поскольку все языки обычно имеют способы делать небезопасные вещи, если человек знает, как с ними бороться.
В C# .NET есть аналогичные положения, и единственный способ объявить конструктор, который вызывает базовый конструктор, - это:
public ClassName(...) : base(...)
при этом базовый конструктор будет вызываться перед телом конструктора, и вы не можете изменить этот порядок.
Я знаю, что это старый вопрос, но мне он понравился, и поэтому я решил дать на него свой собственный ответ. Возможно, мое понимание того, почему этого нельзя сделать, будет способствовать обсуждению и будущим читателям вашего интересного вопроса.
Позвольте мне начать с примера неудачного строительства объекта.
Давайте определим класс A, такой, что:
class A {
private String a = "A";
public A() throws Exception {
throw new Exception();
}
}
Теперь предположим, что мы хотели бы создать объект типа A в блоке try...catch .
A a = null;
try{
a = new A();
}catch(Exception e) {
//...
}
System.out.println(a);
Очевидно, что выход этого кода будет следующим: null .
Почему Java не возвращает частично сконструированную версию A ? В конце концов, к моменту сбоя конструктора поле объекта name уже было инициализировано, верно?
Ну, Java не может вернуть частично построенную версию A , потому что объект не был успешно построен. Объект находится в несогласованном состоянии, и поэтому он отбрасывается Java. Ваша переменная A даже не инициализируется, она сохраняется как null.
Теперь, как вы знаете, чтобы полностью построить новый объект, все его суперклассы должны быть сначала инициализированы. Если один из суперклассов не выполнится, каково будет конечное состояние объекта? Определить это невозможно.
Посмотрите на этот более сложный пример
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(); }
}
При вызове конструктора C , если при инициализации B возникает исключение, каким будет значение конечной переменной int b ?
Таким образом, объект C не может быть создан, он является фиктивным, он является мусором, он не полностью инициализирован.
Для меня это объясняет, почему ваш код является незаконным.
Я не знаю, как Java реализуется внутренне, но если конструктор суперкласса создает исключение, то нет ни одного экземпляра расширяемого класса. Например, было бы невозможно вызвать методы toString() или equals() , поскольку они наследуются в большинстве случаев.
Java может разрешить try / catch вокруг вызова super() в конструкторе, если 1. вы переопределяете методы ALL из суперклассов и 2. вы не используете пункт super.XXX(), но все это кажется мне слишком сложным.
Я не могу предполагать, что у меня есть глубокое понимание внутренних функций Java, но я понимаю, что, когда компилятору нужно создать экземпляр производного класса, он должен сначала создать базу (и ее базу до этого(...)) а затем похлопать по расширениям, сделанным в подклассе.
Так что это даже не опасность непроизвольных переменных или чего-то подобного вообще. Когда вы пытаетесь сделать что-то в подклассе' конструктор перед конструктором базового класса', вы в основном просите компилятор расширить экземпляр базового объекта, который еще не существует.
Edit:In ваш случай, MyClass становится базовым объектом, а MyClassMock -подклассом.
Я знаю, что на этот вопрос есть множество ответов, но я хотел бы дать свой маленький лакомый кусочек о том, почему это не будет разрешено, а именно ответить, почему Java не позволяет вам сделать это. Так что вот, пожалуйста...
Теперь имейте в виду, что super() должен быть вызван до всего остального в конструкторе подкласса, поэтому, если вы использовали блоки try и catch вокруг вашего вызова super() , блоки должны были бы выглядеть следующим образом:
try {
super();
...
} catch (Exception e) {
super(); //This line will throw the same error...
...
}
Если super() fails in the попробуйте block, it HAS to be executed first in the поймать block, so that супер runs before anything in your subclass s конструктор. Это оставляет вас с той же самой проблемой, с которой вы столкнулись в начале: если исключение брошено, оно не поймано. (В этом случае он просто снова бросается в блок catch.)
Так вот, приведенный выше код также никоим образом не разрешен Java. Этот код может выполнить половину первого суперкласса, а затем вызвать его снова, что может вызвать некоторые проблемы с некоторыми суперклассами.
Теперь причина, по которой Java не позволяет вам создать исключение вместо вызова super() , заключается в том, что исключение может быть перехвачено где-то еще, и программа будет продолжать без вызова super() для вашего объекта подкласса, и, возможно, потому, что исключение может принять ваш объект в качестве параметра и попытаться изменить значение унаследованных переменных экземпляра, которые еще не были бы инициализированы.
Один из способов обойти это-вызвать частную статическую функцию. Затем try-catch можно поместить в тело функции.
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);
}
}
}