Почему я не могу использовать TRY блок вокруг моего супер () вызов?

голоса
34

Таким образом, в Java, то первая строка вашего конструктора должен быть вызов супер ... будь то неявного вызова супер (), или явного вызова другого конструктора. То, что я хочу знать, почему я не могу поставить попробовать блок вокруг этого?

Мой конкретный случай является то, что у меня есть макет класс для тестирования. Там нет конструктора по умолчанию не, но я хочу один, чтобы сделать тесты проще читать. Я также хочу, чтобы обернуть исключения, из конструктора в 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, позвольте мне сделать первый?


Моя догадка, как к «почему» является то, что Java не хочет дать мне сконструированный объект в потенциально неустойчивом состоянии ... однако, при этом издеваться, я не забочусь об этом. Кажется, я должен быть в состоянии сделать выше ... или, по крайней мере, я знаю, что выше является безопасным для моего случая ... или кажется, что это должно быть в любом случае.

Я отвергая любые методы, которые я использую от испытанного класса, так что нет никакого риска, что я использую неинициализированные переменные.

Задан 07/08/2008 в 22:17
источник пользователем
На других языках...                            


7 ответов

голоса
14

К сожалению, составители не могут работать на теоретических принципах, и даже если вы знаете, что это безопасно в вашем случае, если они позволят, то она должна была бы быть безопасным для всех случаев.

Другими словами, компилятор не останавливается только вам, это мешает всем, в том числе всех тех, кто не знает , что это небезопасно и требует специальной обработки. Есть , вероятно , другие причины для этого , а также, как и все языки , как правило , есть способы , чтобы сделать небезопасные вещи , если один знает , как бороться с ними.

В C # .NET существуют аналогичные положения, и единственный способ объявить конструктор, который вызывает базовый конструктор заключается в следующем:

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

при этом, базовый конструктор будет вызван перед телом конструктора, и вы не можете изменить этот порядок.

Ответил 07/08/2008 в 22:32
источник пользователем

голоса
2

Я не знаю , как Java реализуется внутри, но если конструктор суперкласса бросает исключение, то есть не экземпляр класса , который вы продлить. Это было бы невозможно назвать toString()или equals()методы, например, поскольку они унаследованы в большинстве случаев.

Java может позволить попробовать / поймать вокруг вызова супер () в конструкторе, если 1. Вы переопределить все методы суперкласса, и 2. Вы не используете () пункт super.XXX, но что все это звучит слишком сложно меня.

Ответил 07/08/2008 в 22:41
источник пользователем

голоса
2

Я не могу себе позволить иметь глубокое понимание Java внутренностей, но это мое понимание того, что, когда компилятор должен создать экземпляр производного класса, он должен сначала создать базу (и ее основание перед тем, что (...)) а затем хлопнуть на продолжениях, сделанных в подклассе.

Так что даже не опасность uninited переменных или что - нибудь подобное на всех. Когда вы пытаетесь сделать что - то в подклассе конструктора до того базового класса конструктор , вы в основном просят компилятор расширить экземпляр базового объекта , который еще не существует.

Изменить: В вашем случае, MyClass становится базовым объектом, и MyClassMock подкласс.

Ответил 07/08/2008 в 22:43
источник пользователем

голоса
5

Это сделано , чтобы предотвратить кто - то от создания нового SecurityManagerобъекта из ненадежного кода.

public class Evil : SecurityManager {
  Evil()
  {
      try {
         super();
      } catch { Throwable t }
      {
      }
   }
}
Ответил 16/09/2008 в 21:55
источник пользователем

голоса
6

Я знаю, что это старый вопрос, но мне понравилось, и как таковой, я решил дать ему ответ самостоятельно. Возможно, мое понимание того, почему это не может быть сделано, будет способствовать обсуждению и будущим читателям вашего интересного вопроса.

Позвольте мне начать с примером непринятия строительства объекта.

Давайте определим класс А, например, что:

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. Ваша переменная А еще не инициализирована, она сохраняется нулевой.

Теперь, как вы знаете, чтобы полностью построить новый объект, все его супер-классы должны быть инициализированы первым. Если один из супер классов не удалось выполнить, что бы конечное состояние объекта? Невозможно определить, что.

Посмотрите на это более сложный пример

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?

Таким образом, объект С не может быть создан, он является поддельным, это мусор, оно не полностью инициализирован.

Для меня, это объясняет, почему ваш код является незаконным.

Ответил 21/04/2012 в 18:09
источник пользователем

голоса
-1

Один из способов обойти это является вызовом собственной статической функции. Примерки улов может быть помещен в теле функции.

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);
     }
  }
}
Ответил 28/03/2014 в 20:35
источник пользователем

голоса
0

Я знаю, что этот вопрос имеет много ответов, но я хотел бы дать свою маленькую пикантную о том, почему это не было разрешено, в частности, ответить, почему Java не позволяет сделать это. Так вот вы идете ...

Теперь, имейте в виду , что super()должен быть вызван , прежде чем что - либо в конструкторе подкласса, поэтому, если вы действительно использовали tryи catchблоки вокруг вашего super()вызова, блоки должны выглядеть следующим образом :

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

Если супер () fails in theпопытаться block, it HAS to be executed first in theпоймать block, so thatсупер runs before anything in your subclassконструктору. Это оставляет вас с той же проблемой , вы имели в начале: если исключение, она не зацепила. (В этом случае он просто получает снова бросил в блоке поймать.)

Теперь, приведенный выше код ни в коей мере допускаемой Java либо. Этот код может выполнить половину первого супер вызова, а затем вызвать его снова, что может вызвать некоторые проблемы с некоторыми супер классами.

Теперь, причина того, что Java не позволяет бросить исключение вместо того, чтобы его призвание в super()том , что исключение может быть пойман где - нибудь еще, и программа будет продолжаться без вызова super()на ваш объект подкласса, и , возможно , потому что исключение может взять объект как параметр и попытаться изменить значение унаследованных переменных экземпляра, которые не еще были инициализированы.

Ответил 17/04/2017 в 15:53
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more