2013-07-12 9 views
15

Gibt es eine Möglichkeit, durch Reflexion herauszufinden, ob ein Konstruktor ein vom Compiler generierter Standardkonstruktor ist oder nicht? Oder gibt es einen anderen Weg?Wird vom Konstruktor ein Standardkonstruktor generiert?

Überraschenderweise gibt die Methode diese Information nicht, so dass es nicht verwendet werden kann. Und es gibt keine Generated Annotation vorhanden.

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 [] 
    } 
} 

Diese Frage stellt das Gleiche, aber für C#: Detect compiler generated default constructor using reflection in C#

+5

Ich denke, die Antwort wäre die gleiche wie C# Antwort :) – PermGenError

+1

Automatische Standardkonstruktor ist definitiv ein Fehler beim Sprachenentwurf.In einer idealen Welt existiert es nicht, also warum kümmert es dich überhaupt? Welche Funktion hängt von der Erkennung des Standardkonstruktors ab? – ZhongYu

+0

Automatische Standard-Konstruktor sind großartig! Es ist für statische Analysen. Wenn ich weiß, dass ein Konstruktor Standard ist, wie ich weiß, indem ich nur die Deklaration der Klasse anschaue, dass sie leer ist und zum Beispiel den "This" -Zeiger nicht an irgendeiner Stelle verliert. – Lii

Antwort

8

Nein, erzeugt der Compiler sie:

ich die Datei erstellt A.java:

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

dann:

javac A.java 

und javap -c A läuft um den Inhalt zu sehen:

public A(){} 

das Ergebnis ist:

es ist identisch
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  
} 

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  
} 

wenn ich den Konstruktor hinzufügen. Ich verwende Java 7 mit 64-Bit-OpenJDK, aber ich wette, dass es bei allen Versionen gleich ist.

BEARBEITEN: tatsächlich garantiert derselbe Bytecode allein nicht, dass die Information nicht als Metadaten vorhanden ist. Unter Verwendung eines Hex-Editors und this program war es möglich zu sehen, dass sich zwei Bytes unterscheiden und den Zeilennummern entsprechen (die zum Drucken von Stapelspuren verwendet werden), so dass die Information in diesem Fall nicht vorhanden ist.

+0

Es scheint sinnvoll, dass ein generierter Standardkonstruktor und ein leerer Konstruktor denselben Bytecode erzeugen. Aber es könnte noch einige Metadaten mit Informationen darüber geben. – Lii

+0

Ah, die Klassendatei in einem Rohdateneditor zu untersuchen sollte es regeln! Vielen Dank. – Lii

5

Nein, im Bytecode gibt es keine Metadaten, mit denen Sie einen vom Compiler generierten Standardkonstruktor von einem nicht generierten unterscheiden können.

In den meisten Fällen sind compilergenerierte Konstruktoren und Methoden mit dem ACC_SYNTHETIC-Flag oder dem Synthetic-Attribut im generierten Bytecode gekennzeichnet. Allerdings gibt es einige bemerkenswerte Ausnahmen gemäß 13.1 Artikel 7 von der Java Language Spec und 4.7.8 vom jvm-spec

Hier wird das entsprechende Bit aus dem JLS:

Alle von einem Java-Compiler eingeführt Konstrukte, die kein entsprechendes Konstrukt im Quellcode haben muss als synthetische gekennzeichnet sein, Ausnahme Standardkonstruktoren, die Klasse Initialisierungsverfahren und die Werte und valueOf Methoden der Enum-Klasse

Soweit ich wissen, javap zeigt nicht die ACC_SYNTHETIC Flag, aber Sie könnten es über isSynthetic lesen, wenn es festgelegt wurde.

+0

'javap -verbose' zeigt Flags, einschließlich' ACC_SYNTHETIC'. –

Verwandte Themen