2016-09-13 3 views
1

Ich habe diese Methode in einer übergeordneten Klasse deklariert:Generische Probleme: T erweitert Interface-Typ. Kann Methode nicht aufrufen, um ein Objekt zurückzugeben, das den Typ erweitert?

protected <ConfigT extends LoadableConfig> ConfigT getConfig(final String configId) { 
    return (ConfigT)getConfigService().getConfig(configId, getDriver()); 
} 

Verfahren Konfigurationsdienst wie folgt definiert ist:

@SuppressWarnings("unchecked") 
@Override 
public <ConfigT extends LoadableConfig> ConfigT getConfig(String configId, WebDriver driver) { 

    //noinspection unchecked 
    Map<String,LoadableConfig> profile = profiles.get(getProfileName(driver)); 

    if(profile != null) { 
     return (ConfigT) profile.get(configId); 
    } 

    return null; 
} 

Die Konfiguration Typ I ist hier wollen:

public interface AccessibleConfig extends LoadableConfig, PolleableConfig { 
.... 
} 

Diese Codezeile verursacht einen inkompatiblen Typenfehler:

AccessibleConfig config = getConfig(ValidationPane.class.getCanonicalName()); 

Wie ist das möglich? Die AccessibleConfig verlängert LoadableConfig. Die aufgerufene Methode deklariert, dass dieser Rückgabetyp ein Typ ist, der LoadableConfig erweitert. Ich betreibe jdk1.8.0_102.jdk. Dieser Fehler tritt sowohl in IntelliJ als auch beim Kompilieren mit Maven von der Befehlszeile auf. Ich bin in der Lage, dies mit anderen Konfigurationstypen zu tun, die den LoadableConfig Typ erweitern.

EDIT:

Übergeordnete Klasse:

public abstract class AbstractLoadable<T extends AbstractLoadable<T>> { 

    private Map<String,LoadableConfig> profiles = new HashMap<>(); 

    protected <T extends LoadableConfig> T getConfig(final String configId) { 
     return (T) profiles.get(configId); 
    } 
} 

Betonklasse:

public class ConcreteLoadable extends AbstractLoadable { 

    public ConcreteLoadable(final String profileName) { 

     AccessibleConfig config = getConfig(ConcreteLoadable.class.getCanonicalName()); 
    } 

} 

Und die Schnittstellentypen:

public interface LoadableConfig { 
    Integer getLoadTimeoutInSeconds(); 
    void setLoadTimeoutInSeconds(final Integer loadTimeoutInSeconds); 
} 

public interface AccessibleConfig extends LoadableConfig { 
    Boolean getHoverOverAccessorWithJavascript(); 
    void setHoverOverAccessorWithJavascript(final Boolean hoverOverAccessorWithJavascript); 
    Boolean getClickAccessorWithJavascript(); 
    void setClickAccessorWithJavascript(final Boolean clickAccessorWithJavascript); 
} 

Also, welche die Ausübung dieses minimal Herstellung So wurde es zum Beispiel wirklich leicht gemacht, die Quelle des Compilerfehlers zu identifizieren. Ich habe unten eine Antwort auf diese Frage gepostet. Demütig akzeptiere ich, dass ich eigentlich kein vollständiges Beispiel postulierte.

+0

Wie wärs mit einem minimal, _complete_ Beispiel, das zeigt dies? Es gibt viele lose Enden hier. –

+1

Randnotiz zur Benennung: Die Konvention soll ** einzelne ** Zeichen für Typparameter verwenden. Nennen Sie es einfach T, nicht ConfigT. Alles andere wird jeden leicht erfahrenen Java-Programmierer verwirren. – GhostCat

+0

@GhostCat Es kann auf alle Großbuchstaben erweitert werden, aber nur in Sonderfällen mit vielen Parametern. CamelCase ist definitiv das Schlimmste. –

Antwort

1

Ich habe das Problem identifiziert. Die konkrete Klasse muss sich selbst an das übergeordnete Element übergeben, da das übergeordnete Element reflexiv generisch ist. Die Fehlermeldung war nicht sehr hilfreich, also wurde ich damit beschäftigt, über die generischen Parameter der übergeordneten Klassenmethode nachzudenken und nicht über die generischen Parameter, die auf die Elternklasse selbst angewendet wurden.

Die Klassendeklaration für ConcreteLoadable Anforderungen an das geändert zu den Kompilierung-Fehlern loszuwerden:

public class ConcreteLoadable extends AbstractLoadable<ConcreteLoadable> { 

    public ConcreteLoadable(final String profileName) { 

     AccessibleConfig config = getConfig(ConcreteLoadable.class.getCanonicalName()); 
    } 

} 
Verwandte Themen