2015-04-19 11 views
10

Ho un interfaccia che si presenta sostanzialmente in questo modo:Come rendere questo Java 7 compatibile?

public interface ISetting<T> { 
    public T getDefault(); 
    public T value(); 
    public void set(T value); 
    public String getName(); 

    public default String getValueName() { 
     Object obj = value(); 
     if (obj instanceof Boolean) { 
      return (boolean)obj ? "Yes" : "No"; 
     } 

     return obj.toString(); 
    } 
} 

E poi in un'altra classe ho un elenco di ISetting<?>

private List<ISetting<?>> settings = Arrays.asList(
     new ClassMode(), 
     new EndMode(), 
     new PlayerLives(), 
     new JoinMidGame(), 
     new ScoreboardDisplay(), 
     new LifePerKill(), 
     new ExplosiveBullets(), 
     new ReloadTime()); 

E questo tutto funziona perfettamente! Tuttavia, la piattaforma in cui utilizzo il mio codice non supporta Java 8, quindi devo usare Java 7, ed ecco dove arrivano i problemi.

se ho impostato il target a 1,7 Maven, come questo nel mio pom.xml:

<configuration> 
    <source>1.8</source> 
    <target>1.7</target> 
</configuration> 

Quindi il codice compila perfettamente senza errori o altro. Tuttavia, quando si tenta di eseguire il codice, mi dà questo errore:

java.lang.ClassFormatError: Method getValueName in class net/uniqraft/murder/match/settings/ISetting has illegal modifiers: 0x1

ho cercato su Google, ma non ho trovato nulla che ho capito o sembrava di essere applicabile nel mio caso.

Così, ho pensato, mi rifarò l'intero codebase in Java 7:

<configuration> 
    <source>1.7</source> 
    <target>1.7</target> 
</configuration> 

Il primo errore che vedo è:

Default methods are allowed only at source level 1.8 or above

che è incredibilmente fastidioso e io non so come bypassarlo. Gran parte del mio codice dipende dalle implementazioni predefinite. Suppongo che dovrei semplicemente usare le classi astratte, invece?

Ma l'errore più problematico quello che vedo è il List<Setting<?>> ho:

Type mismatch: cannot convert from List<ISetting<? extends Object&Comparable<?>&Serializable>> to List<ISetting<?>>

Non ho idea di che cosa ciò significhi o come risolvere il problema. Le offerte rapide di Eclipse non sono di aiuto.

Nel caso in cui l'avete bisogno di vedere l'intera classe non-spogliato ISetting o stacktrace piena, li ho messi esternamente come sono piuttosto Spacey:

+1

Maven non dovrebbe consentire questa combinazione di origine/destinazione; il compilatore java non lo accetterà, quindi Maven potrebbe bloccare silenziosamente le impostazioni per il targeting di -target 1.8? Penso che tu ti stia addormentando in un falso senso di confidenza da parte di Maven, non venendo a mancare immediatamente alla compilazione. –

+3

Ma la risposta breve è: i metodi predefiniti sono una funzionalità di Java 8 e richiedono il supporto dalla VM di Java 8. –

risposta

8

dividerò la risposta in due parti, la prima relativa inferenza di tipo e le seconde riguardanti metodi predefiniti:

inferenza di tipo

In Java 7, il tipo di un'espressione è la stessa, indipendentemente dal contesto. Così, quando si fa:

Arrays.asList(new ClassMode(), new EndMode(), ...); 

Non crea un List<ISetting<?>>. È possibile farlo funzionare modificando il tipo settings su List<? extends ISetting<?>>. Cioè, un elenco che può contenere elementi che possono essere un ISetting<?> o qualsiasi sottotipo di esso:

List<? extends ISetting<?>> settings = Arrays.asList(new ClassMode(), new EndMode(), ...); 

In Java 8, assegnando la lista risultante a un List<ISetting<?>> opere a causa della poly expressions. Ciò significa che il tipo dedotto di alcune espressioni può essere influenzato dal tipo di destinazione. Così, quando si fa:

private List<ISetting<?>> settings = Arrays.asList(new ClassMode(), new EndMode(), ...); 

Il compilatore analizza il tipo di destinazione e, implicitamente, passa un parametro di tipo a Arrays.asList(), che equivale a fare:

private List<ISetting<?>> settings = Arrays.<ISetting<?>>asList(new ClassMode(), new EndMode(), ...); 

che crea un List<ISetting<?>> e lo assegna a settings. Il modulo precedente funziona anche in Java 7, se non si desidera modificare il tipo settings.

metodi predefiniti

Java 7 non ha metodi predefiniti. Invece, potresti creare un'implementazione di scheletro astratta insieme alla tua interfaccia. L'interfaccia definirà il tipo e l'implementazione dello scheletro fornirà la funzionalità predefinita.

In primo luogo, girare le default metodi tua interfaccia in dichiarazioni di metodo regolari:

public interface ISetting<T> { 
    T getDefault(); 
    T value(); 
    void set(T value); 
    String getName(); 

    // Former default methods: 
    String getValueName(); 
    boolean isHidden(); 
    boolean isDefault(); 
    // etc. 
} 

Quindi creare una classe astratta per contenere le implementazioni di default:

public abstract class AbstractSetting<T> implements ISetting<T> { 

    @Override 
    public String getValueName() { 
     Object obj = value(); 
     if (obj instanceof Boolean) { 
      return ((Boolean) obj) ? "Yes" : "No"; 
     } 
     return obj.toString(); 
    } 

    @Override 
    public boolean isHidden() { 
     return false; 
    } 

    // etc. 
} 

Ora fate le vostre classi concrete attuare il Interfaccia ISetting<T> ed estendere la classe AbstractSetting<T>. Ad esempio:

public class ConcreteSetting extends AbstractSetting<Boolean> implements ISetting<Boolean> { 
    // concrete implementation 
} 
+0

Grazie per l'ottima risposta! Userò l'implementazione scheletrica astratta. Solo una domanda però. L'estensione di 'AbstractSetting ' non fa che implementare 'ISetting '?Segnalo come risposta accettata una volta che l'ho implementato nel mio codice. –

+2

@VapidLinus Felice di aiutare! Sì, puoi omettere quella parte senza problemi. L'ho messo lì per chiarire che 'ConcreteSetting' implementa' ISetting 'e che l'estensione di' AbstractSetting 'è solo un dettaglio di implementazione. Questo è lo stesso stile utilizzato nella dichiarazione 'ArrayList ' 'classe ArrayList extends AbstractList implementa l'elenco '. –

5

È necessario eseguire una delle seguenti operazioni:

  • rimuovere predefinito m odificatore da getValueName()
  • rendere [abstract] classe anziché interfaccia
  • aggiornare la piattaforma a Java 1.8
Problemi correlati