2013-07-12 22 views
15

Czy istnieje sposób, aby dowiedzieć się przez refleksję, czy konstruktor jest konstruktorem domyślnym generowanym przez kompilator, czy też nie? Czy jest jakiś inny sposób?Czy konstruktor generuje domyślny konstruktor?

Nieoczekiwanie metoda isSynthetic nie podaje tych informacji, więc nie można ich użyć. I nie ma adnotacji Generated.

public class JavaTest { 
    public void run() throws Exception { 
     out.println(JavaTest.class.getConstructors()[0].isSynthetic()); // Prints false 
     out.println(Arrays.asList(JavaTest.class.getConstructors()[0].getAnnotations())); // Prints [] 
    } 
} 

To pytanie zadaje to samo, ale dla C#: Detect compiler generated default constructor using reflection in C#

+5

Myślę, że odpowiedź byłaby taka sama jak odpowiedź C# :) – PermGenError

+1

Automatyczny konstruktor domyślny jest zdecydowanie błędem w projektowaniu języka.W idealnym świecie nie istnieje, więc dlaczego tak ci na tym zależy :) Jaka funkcja zależy od wykrycia domyślnego konstruktora? – ZhongYu

+0

Automatyczny konstruktor domyślny jest świetny! To do analizy statycznej. Jeśli wiem, że konstruktor jest domyślny, niż ja wiem, tylko patrząc na deklarację klasy, jest on pusty i na przykład nie przecieka tego wskaźnika. – Lii

Odpowiedz

8

nr kompilator je generuje:

stworzyłem plik A.java:

public class A{ 
public String t(){return "";} 
} 

następnie:

javac A.java 

i działa javap -c A aby zobaczyć treść:

Compiled from "A.java" 
public class A { 
    public A(); 
    Code: 
     0: aload_0  
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return   

    public java.lang.String t(); 
    Code: 
     0: ldc   #2     // String 
     2: areturn  
} 

jeśli dodać konstruktora:

public A(){} 

wynikiem jest:

Compiled from "A.java" 
public class A { 
    public A(); 
    Code: 
     0: aload_0  
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return   

    public java.lang.String t(); 
    Code: 
     0: ldc   #2     // String 
     2: areturn  
} 

to identyczne. Używam Java 7 z 64-bitowym OpenJDK, ale założę się, że jest taka sama dla wszystkich wersji.

EDIT: w rzeczywistości sam kod bajtowy nie gwarantuje, że informacje nie są obecne jako metadane. Za pomocą edytora szesnastkowego i this program można było zauważyć, że istnieją dwa bajty różniące się i odpowiadają numerom linii (używanym do drukowania śladów stosu), więc w tym przypadku informacja jest nieobecna.

+0

To wydaje się rozsądne, że wygenerowany domyślny konstruktor i pusty konstruktor generują ten sam kod bajtowy. Ale nadal mogą istnieć pewne metadane z informacjami na ten temat. – Lii

+0

Ah, zbadanie pliku klasy w edytorze danych surowych powinno go załatwić! Dzięki. – Lii

5

Nie, nie ma metadanych w kodzie bajtowym, które pozwoliłyby odróżnić konstruktor domyślny wygenerowany przez kompilator od nie wygenerowanego.

W większości przypadków konstruktory i metody generowane przez kompilator są oznaczone flagą ACC_SYNTHETIC lub atrybutem Synthetic w wygenerowanym kodzie bajtowym. Jednakże, istnieje kilka wyjątki jak na 13,1 pkt 7 od Java Language Spec i 4.7.8 z jvm-spec

Oto istotne nieco z JLS:

Wszelkie konstrukcje wprowadzone przez kompilator Javy, która nie mieć odpowiedni konstrukt kodu źródłowego muszą być oznaczone jako syntetyczny, wyjątkiem domyślnych konstruktorów, sposób inicjalizacji klasy i wartości i metod valueOf klasy wyliczeniowego

ile i know, javap nie wyświetla flagi ACC_SYNTHETIC, ale można ją odczytać przez isSynthetic, jeśli została ustawiona.

+0

'javap -verbose' wyświetla flagi, w tym' ACC_SYNTHETIC'. –

Powiązane problemy