2009-09-03 3 views

ответ

324

Да, конструкторы могут исключать исключения. Обычно это означает, что новый объект сразу же подходит для сбора мусора (хотя его, возможно, не собирают в течение некоторого времени, конечно). Возможно, что «полуконструированный» объект будет придерживаться, хотя, если он стал видимым ранее в конструкторе (например, назначив статическое поле или добавив себя в коллекцию).

Остерегайтесь бросать исключения в конструкторе: поскольку вызывающий объект (обычно) не будет использовать новый объект, конструктор должен быть осторожным, чтобы избежать получения неуправляемых ресурсов (файлы и т. Д.) И затем бросая исключение, не отпуская их. Например, если конструктор пытается открыть FileInputStream и FileOutputStream, а первый успешно завершается, а второй терпит неудачу, вы должны попытаться закрыть первый поток. Это становится сложнее, если это конструктор подкласса, который генерирует исключение, конечно ... все становится немного сложнее. Это не проблема очень часто, но это стоит рассмотреть.

+25

+1. Никто обычно не думает об исключениях, брошенных подклассами. –

+1

@JonSkeet: ** Не могли бы вы дать нам пример кода о ** *, если он стал видимым ранее в конструкторе (например, назначив статическое поле или добавив себя в коллекцию). *? – Tarik

+3

@Tarik: Ну, пример кода будет делать именно это - например. 'someStaticField = this;' или 'someCollection.add (this)' внутри конструктора. –

31

Абсолютно.

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

7

Да.

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

+0

Важная вещь в вашем заявлении - «специальные методы». Поэтому они не похожи ни на какой другой метод. Выброс исключения из конструктора без конечного класса ** мог бы создать дыру в безопасности, поэтому при принятии решения об этом нужно проявлять особую осторожность. См. Ответ от @Billy выше, с выпиской из Java Secure Coding Guidelines. –

11

Да, конструкторам разрешено исключать исключения.

Однако будьте очень мудры в выборе каких исключений они должны быть - проверены исключения или непроверены. Исключенные исключения - это в основном подклассы RuntimeException.

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

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

76

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

следующее: Secure Coding Guidelines 2.0.

Частично инициализированные экземпляры не конечного класса могут быть доступны посредством атаки финализатора. Атакующий переопределяет защищенный метод finalize в подклассе и пытается создать новый экземпляр этого подкласса. Эта попытка не выполняется (в приведенном выше примере проверка SecurityManager в конструкторе ClassLoader вызывает исключение безопасности), но злоумышленник просто игнорирует любое исключение и ожидает, что виртуальная машина выполнит финализацию на частично инициализированном объекте. Когда это происходит, вызывается реализация метода злонамеренного финализа, предоставляющая злоумышленнику доступ к этому, ссылка на завершаемый объект. Хотя объект только частично инициализирован, злоумышленник все равно может вызывать методы на нем (тем самым обходя проверку SecurityManager).

+1

Означает ли это, что бросание из не-конечного класса является нарушением безопасности? Это еще проблема? – kroiz

+1

Обратите внимание, что это руководство имеет значение только в том случае, если ваш код является или может использоваться в контексте важности безопасности. Например, большинство Java-кода используются в контекстах, где нет SecurityManager. –

0

Конструктор МОЖЕТ выбрасывать любое исключение. Но если какой-либо конструктор подкласса вызывает конструктор суперкласса, который генерирует исключение, то конструктор подкласса должен либо поймать исключение, либо выбросить его.

+8

Конструктор подкласса не может поймать исключение, так как использование блока try до того, как super() вызовет ошибку компиляции («вызов super должен быть первым выражением в конструкторе») –

10

Да, он может бросить исключение, и вы можете заявить, что в подписи конструктора тоже, как показано в следующем примере:

public class ConstructorTest 
{ 
    public ConstructorTest() throws InterruptedException 
    { 
     System.out.println("Preparing object...."); 
     Thread.sleep(1000); 
     System.out.println("Object ready"); 
    } 

    public static void main(String ... args) 
    { 
     try 
     { 
      ConstructorTest test = new ConstructorTest(); 
     } 
     catch (InterruptedException e) 
     { 
      System.out.println("Got interrupted..."); 
     } 
    } 
} 
-1

да это может бросить исключение, как другой метод делает

+1

Большое спасибо за этот подробный ответ, хотя этот вопрос на который были получены ответы гораздо лучше. – Tom

Смежные вопросы