2016-02-04 22 views
6

Mi piacerebbe avere una classe non generica in kotlin che usi i generici nel suo costruttore per specificare che un parametro. Tuttavia, non riesco a capire come farlo, e il convertitore Java-to-Kotlin per le interruzioni Intellij.Una classe non generica accetta un argomento generico nel costruttore

mia classe Java sembra uscita questa

public class Test {  
    interface I1 { }  
    interface I2 { } 

    private final I1 mI1; 
    private final I2 mI2; 

    public <T extends I1 & I2> Test(T host) { 
     mI1 = host; 
     mI2 = host; 
    } 
} 

del convertitore simile a questa.

class Test(host: T) where T: I1, T: I2 { 
    internal interface I1 
    internal interface I2 

    private val mI1: I1 
    private val mI2: I2 

    init { 
     mI1 = host 
     mI2 = host 
    } 
} 

vorrei fare questo perché in fase di sviluppo Android è utile essere in grado di specificare un parametro del costruttore che assomiglia <Host extends Context & CustomCallbackInterface>

risposta

5

Guardando Kotlin di grammar, sembra che questo non è possibile al momento. Per i costruttori primari, i parametri di tipo denotano parametri di tipo classe:

class (used by memberDeclaration, declaration, toplevelObject) 
    : modifiers ("class" | "interface") SimpleName 
     typeParameters? 
     primaryConstructor? 
     (":" annotations delegationSpecifier{","})? 
     typeConstraints 
     (classBody? | enumClassBody) 
    ; 

per i costruttori secondari, non ci sono parametri di tipo possibile:

secondaryConstructor (used by memberDeclaration) 
    : modifiers "constructor" valueParameters (":" constructorDelegationCall)? block 
    ; 

Tuttavia, un costruttore è solo una funzione speciale. Se invece non usiamo il costruttore, ma una funzione della nostra, siamo in grado di venire con il seguente:

class Test { 

    interface I1 

    interface I2 

    private val mI1: I1 
    private val mI2: I2 

    internal constructor(host: I1, host2: I2) { 
     mI1 = host 
     mI2 = host2 
    } 

    companion object { 

     fun <T> create(host: T): Test where T : Test.I1, T : Test.I2 { 
      return Test(host, host) 
     } 

    } 
} 

fun <T> test(host: T): Test where T : Test.I1, T : Test.I2 { 
    return Test(host, host) 
} 

Ora possiamo chiamare Test.create(host) o test(host) per creare un'istanza.

+1

Questo è chiamato "una fabbrica". Sarebbe bene spiegare l'oggetto compagno in una frase. Anche l'annotazione @JvmStatic che potrebbe essere utile qui se vogliono chiamare la factory come se fosse una statica di classe. –

2

Ampliando nhaarman 's answer è possibile utilizzare operator overloading per fare Test' s companion object implementare la invokeoperator:

class Test { 

    interface I1 

    interface I2 

    private val mI1: I1 
    private val mI2: I2 

    private constructor(i1: I1, i2: I2) { 
     mI1 = i1 
     mI2 = i2 
    } 

    companion object { 
     operator fun <T> invoke(host: T): Test where T : I1, T : I2 { 
      return Test(host, host) 
     } 
    } 
} 

È quindi possibile creare un oggetto Test utilizzando la sintassi di chiamata che si desidera:

Test(object : Test.I1, Test.I2 {}) 
+0

I problemi con questo approccio è che non è un vero costruttore dal punto di vista di Java o altri linguaggi JVM (se questo è importante), per quelli il nome sarà strano se trovassero anche la funzione (@JvmStatic sarebbe d'aiuto). E anche la riflessione non la vedrà come un costruttore (anche in questo caso potrebbe non avere importanza). –

Problemi correlati