2015-01-02 12 views
20

Mam bardzo dziwny błąd kompilacji:nie można uzyskać dostępu do pola z kontekstu statycznego podczas przechodzenia wartość superkonstruktor

class Super { 
    Super(int[] array) { 

    } 
} 

class Sub extends Super { 
    private final int number = 1; 

    Sub() { 
     super(new int[] { number }); //error 
    } 
} 

Błąd pojawia jest

Cannot access field from static context

Moje pytanie

Gdzie jest kontekst statyczny? Wygląda na to, że nawet statyczne nie odgrywają tutaj żadnej roli.

Natknąłem się na tę próbę odpowiedzi na cudze pytanie; znalazłem błąd, który wprawił mnie w zakłopotanie. Czy ktoś może wyjaśnić, gdzie znajduje się kontekst statyczny?

+1

Z którego kompilatora korzystasz? Dostaję 'nie można podać numeru, zanim został wywołany konstruktor supertype'. Zobacz także JLS 8.8.7.1. _Explicit Constructor Invocations_, które stwierdza: _ "Wyraźna instrukcja wywołania konstruktora w ciele konstruktora może nie odwoływać się do zmiennych instancji lub metod instancji lub klas wewnętrznych zadeklarowanych w tej klasie lub jakiejkolwiek nadklasie, lub użyć tego lub super w dowolnym wyrażeniu; pojawia się błąd podczas kompilacji. "_ –

+0

@ZouZou Pierwszy raz natknąłem się na AIDE mojego telefonu, który jestem pewien, używa kompilatora Dalvik. Potem wskoczyłem na komputer, aby wypróbować go na Eclipse Luna, używając ich kompilatora JDK 8u25 i otrzymałem ten sam komunikat o błędzie. Nie jestem pewien, dlaczego daje mi to statyczny błąd kontekstu, więc myślę, że powinienem ponownie zainstalować Eclipse. Jeśli chodzi o AIDE, nie jestem zbyt zaskoczony, że dał mi ostry błąd –

Odpowiedz

4

Od JLS 8.8.7

An explicit constructor invocation statement in a constructor body may not refer to any instance variables or instance methods or inner classes declared in this class or any superclass, or use this or super in any expression; otherwise, a compile-time error occurs.

W czasie rozmowy super instancją Sub nie będzie jeszcze istnieć

+0

+ 1. Myślę, że twoje ostatnie zdanie jest kluczową kwestią. Ponieważ nie istnieje tam żadna instancja, kompilator ma sens, aby uznać ją za "kontekst statyczny", podobnie jak w przypadku metody statycznej lub statycznego bloku inicjalizacyjnego, lub inicjującego wyrażenia pola statycznego. (Osobiście uważam, że kompilator lepiej byłoby użyć oddzielnego komunikatu o błędzie dla tego kontekstu, tylko dla jasności i uniknięcia pomyłki, ale ograniczenia są takie same jak w normalnych kontekstach statycznych, więc autorzy kompilacji byli prawdopodobnie zbyt kuszeni nie powtarzać się.) – ruakh

6

Twoje pole number powinno być statyczne, aby można było używać go w wywołaniu konstruktora. W przeciwnym razie otrzymasz cannot reference number before supertype constructor has been called, ponieważ pole nie jest dostępne przed wywołaniem konstruktora klasy nadrzędnej.

więc kod powinien wyglądać następująco:

class Super { 
    Super(int[] array) { 

    } 
} 

class Sub extends Super { 
    private static final int number = 1; 
    Sub() { 
     super(new int[] { number }); //error 
    } 
} 
4

Chodzi o to, super musi zostać wywołana zanim cokolwiek innego odbywa się w podklasie. Oznacza to, że number nie został zainicjalizowany w czasie połączenia, więc nie można go przekazać super. Co do tego, co to ma wspólnego z "statycznym kontekstem", nie jestem pewien.

0

Spróbuj uruchomić następujący program.

public class Main { 

    public static class Super 
    { 
     Super(int number) { 
      System.out.println("A"); 
     } 
    } 

    public static class Sub extends Super { 

     private final Thing thing = new Thing(); 

     Sub() { 
      super(3); 
      System.out.println("B"); 
     } 
    } 

    public static final class Thing { 
     Thing() { 
      System.out.println("C"); 
     } 
    } 

    public static void main(String[] args) { 
     new Sub(); 
    } 
} 

wyjście jest, C i B. Pierwsza konstruktor Super biegów, wówczas pole przykład thing z Sub jest inicjowany. W końcu wykonywane są linie konstruktora Sub po super.

Podczas próby odniesienia się do number, pole number nie zostało jeszcze zainicjalizowane i nie ma instancji Sub. Komunikat o błędzie może być bardziej pomocny. Na IntelliJ dostaję "Nie można odwołać się do numeru podrzędnego zanim został wywołany konstruktor supertype".

0

Ładowanie zajęć odbywa się z klasy dziecka (jeśli jej metody mające główną lub spowodowane przez inne klasy obciążenia) do klasy bazowej, ale inicjalizacji dzieje się w odwrotnej kolejności (Klasa bazowa zostanie zainicjowany pierwszy). Inicjowanie klasy bazowej odbywa się wcześniej, w tym czasie twoje pole numeru nie będzie istniało, ponieważ jest zmienną instancji.

Można zrobić to statyczne (zmienna klasa) załadować wcześniej i jeśli jego końcowy następnie kompilator dokona wpisu stałej puli w czasie kompilacji only.so że JVM będzie w stanie uzyskać jego wartość.