2009-09-03 10 views

Odpowiedz

324

Tak, konstruktorzy mogą zgłaszać wyjątki. Zwykle oznacza to, że nowy obiekt od razu kwalifikuje się do zbierania śmieci (choć oczywiście może nie być gromadzony przez jakiś czas, oczywiście). Możliwe jest, że obiekt "na wpół skonstruowany" będzie się trzymał, jeśli jest widoczny wcześniej w konstruktorze (np. Przez przypisanie pola statycznego lub dodanie się do kolekcji).

Jedną z rzeczy, na którą należy zwrócić uwagę przy rzucaniu wyjątków w konstruktorze: ponieważ osoba wywołująca (zwykle) nie będzie miała możliwości korzystania z nowego obiektu, konstruktor powinien uważać, aby nie uzyskać zasobów niezarządzanych (uchwyty plików itp.) I następnie rzucając wyjątek bez zwalniania ich. Na przykład, jeśli konstruktor próbuje otworzyć FileInputStream i FileOutputStream, a pierwszy z nich się powiedzie, ale drugi się nie powiedzie, powinieneś spróbować zamknąć pierwszy strumień. To staje się trudniejsze, jeśli jest to konstruktor podklasy, który rzuca wyjątek, oczywiście ... wszystko staje się nieco trudne. To nie jest problem bardzo często, ale warto się nad tym zastanowić.

+25

+1. Nikt zwykle nie myśli o wyjątkach wyrzucanych przez podklasy. –

+1

@JonSkeet: ** Czy możesz podać nam przykład kodu o * *, jeśli jest widoczny wcześniej w konstruktorze (np. Przypisując pole statyczne lub dodając się do kolekcji). *? – Tarik

+3

@Tarik: Cóż, przykład kodu zrobiłby dokładnie to - np. 'someStaticField = this;' lub 'someCollection.add (this)' w konstruktorze. –

31

Absolutnie.

Jeśli konstruktor nie otrzyma prawidłowego wejścia lub nie może zbudować obiektu w prawidłowy sposób, nie ma innego wyjścia niż wyrzucenie wyjątku i powiadomienie swojego rozmówcy.

7

Tak.

Konstruktory są niczym więcej niż specjalnymi metodami i mogą generować wyjątki, tak jak każdą inną metodę.

+0

Ważną rzeczą w twoim oświadczeniu jest "specjalne metody". Więc nie są jak żadna inna metoda. Zgłoszenie wyjątku od nieostatniego konstruktora klasy ** może ** stworzyć lukę bezpieczeństwa, dlatego należy zachować szczególną ostrożność, decydując się na to. Zobacz odpowiedź @Billy powyżej, z wyciągiem z Java Secure Coding Guidelines. –

11

Tak, konstruktorzy mogą zgłaszać wyjątki.

Należy jednak bardzo mądrze określić, jakie wyjątki powinny być - wyjątki zaznaczone lub odznaczone. Niezaznaczone wyjątki są w zasadzie podklasami RuntimeException.

W prawie wszystkich przypadkach (nie mogłem wymyślić wyjątku w tej sprawie), trzeba rzucić sprawdzony wyjątek. Powodem jest to, że niezaznaczone wyjątki (takie jak wyjątek NullPointerException) są zwykle spowodowane błędami programowania (takimi jak niewystarczająca weryfikacja danych wejściowych).

Zaletą, którą oferuje sprawdzany wyjątek, jest to, że programista jest zmuszony wychwycić wyjątek w swoim kodzie wystąpienia, a tym samym zdaje sobie sprawę, że wystąpienie błędu wystąpienia instancji obiektu może być niemożliwe. Oczywiście, tylko przegląd kodu złapie słabą praktykę programowania połknięcia wyjątku.

76

Tak, mogą zgłaszać wyjątki. Jeśli tak, zostaną tylko częściowo zainicjowane, a jeśli nie są ostateczne, podlegają atakowi.

Poniżej znajduje się od Secure Coding Guidelines 2.0.

Częściowo zainicjowane wystąpienia klasy nieostatniej można uzyskać za pomocą ataku finalizatora. Atakujący zastępuje chronioną metodę finalizacji w podklasie i próbuje utworzyć nową instancję tej podklasy. Ta próba nie powiodła się (w powyższym przykładzie sprawdzanie menedżera SecurityManager w konstruktorze ClassLoader powoduje zgłoszenie wyjątku dotyczącego zabezpieczeń), ale osoba atakująca po prostu ignoruje każdy wyjątek i czeka, aż maszyna wirtualna wykona finalizację częściowo zainicjowanego obiektu. Gdy to nastąpi, wywoływana jest implementacja złośliwej metody finalizacji, umożliwiając atakującemu dostęp do tego, odniesienie do finalizowanego obiektu. Chociaż obiekt jest inicjowany tylko częściowo, atakujący może nadal wywoływać na nim metody (dzięki temu obejście kontroli SecurityManager).

+1

Czy oznacza to, że rzucanie z klasy przedostatniej jest naruszeniem bezpieczeństwa? Czy to nadal jest problem? – kroiz

+1

Należy pamiętać, że ta wytyczna jest ważna tylko wtedy, gdy kod jest lub może być używany w kontekście, w którym bezpieczeństwo jest ważne. Na przykład większość kodu Java jest używana w kontekstach, w których nie ma aplikacji SecurityManager. –

0

Konstruktor MOŻE rzucić wyjątek. Ale jeśli konstruktor podklasy wywoła konstruktor super klasy, który zgłasza wyjątek, konstruktor podklasy musi albo przechwycić wyjątek, albo go rzucić.

+8

Konstruktor podklasy nie może wychwycić wyjątku, ponieważ użycie bloku try przed super() spowoduje błąd kompilacji ("call to super musi być pierwszą instrukcją w konstruktorze") –

10

Tak, może to wyjątek i może zadeklarować, że w podpisie konstruktora też, jak pokazano w poniższym przykładzie:

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

tak może to wyjątek jak inne metody nie

+1

Dziękuję bardzo za tę szczegółową odpowiedź, chociaż to pytanie odpowiedział już znacznie lepiej. – Tom

Powiązane problemy