2013-03-13 11 views
7

Ho giocato con il pacchetto rJava, ma poiché sembra che rJava non sia a conoscenza dei tipi generici Java, ho difficoltà a creare oggetti java con parametri di tipo generico. Se ho una classe Java come:rJava generics tipo

public class A<T> { 
    private B<T> b; 
    public A(B<T> b) { 
     this.b = b; 
    } 
} 

Vorrei creare un Un oggetto dalla sessione di R usando .jnew() passando un oggetto B già creato (con il parametro di tipo istanziato), ma Rjava dà sempre errore:

java.lang.NoSuchMethodError: <init> 

C'è qualche soluzione per questo?

+0

Qual è la sintassi esatta che stai usando quando chiami '.jnew()'? Stai passando argomenti?Si prega di specificarli esattamente. – Brick

+0

Ecco un esempio funzionante. Dovrai scaricare il barattolo di Tetrad da [qui] (http://www.phil.cmu.edu/projects/tetrad_download/download/tetrad-5.2.1-3.jar) (19mb) e il set di dati di esempio, charity.txt, da [qui] (http://www.phil.cmu.edu/projects/tetrad_download/download/workshop/Data/charity.txt). Configura in R: 'setwd (" dovunque/tu/metti/i/data/")', 'library (rJava)', '.jinit (" percorso/a/tetrad-5.2.1-3.jar ")'. Tutti i seguenti lavori: 1. 'filename = .jnew (" java/lang/String "," charity.txt ")', 2. 'datafile = .jnew (" java/io/File ", nomefile)', 3. 'reader = .jnew (" edu/cmu/tetrad/data/DataReader ")', –

+0

4. 'delim = J (" edu/cmu/tetrad/data/DelimiterType ")', 5. 'reader $ setDelimiter (delim $ TAB) ', 6.' dataset = reader $ parseTabular (datafile) '. Ma quanto segue non funziona: 7. 'gesinstance = .jnew (" edu/cmu/tetrad/search/Ges ", dataset)'. reader $ parseTabular restituisce un DataSet e la classe Ges dovrebbe essere creata con un argomento DataSet. Sfortunatamente questo non funziona. Penso che la ragione sia perché Ges implementa due interfacce, GraphSearch e GraphScorer, e GraphScorer è solo un doppio. Nel sorgente Java: 'interfaccia pubblica GraphScorer { double scoreDag (Graph dag); } ' –

risposta

1

Ci sono molte parti mobili in questa domanda. Scavando attraverso la documentazione per le varie parti, penso che avete bisogno di fare questo sulla linea che ha fatto traboccare:

gesinstance = .jnew("edu/cmu/tetrad/search/Ges", .jcast(dataset, "edu/cmu/tetrad/data/DataSet")) 

La differenza chiave è la chiamata al .jcast sul secondo argomento. (Non ho installato R, quindi non ho potuto testarlo - Se non funziona, aggiornerò la mia risposta sulla base di qualsiasi feedback che puoi fornire sui nuovi messaggi di errore.)

Quindi la domanda è "perché quel?" La risposta sembra essere:

  1. Sul lato Java, DataReader.parseTabularData restituisce un oggetto con tipo DataSet come avrete notato, ma è un DataSet non un'interfaccia una classe. Ciò significa necessariamente che l'oggetto restituito è di una classe che implementa l'interfaccia DataSet.
  2. Per motivi che non mi sono immediatamente chiari, il pacchetto rJava non gestisce bene il polimorfismo. Richiede che chiami metodi con una corrispondenza di firma "esatta" con gli oggetti che stai passando. In questo caso, dovrai "up-cast" da qualsiasi classe specifica che hai sull'interfaccia DataSet. Vedere la documentazione per .jnew (https://www.rforge.net/doc/packages/rJava/html/jnew.html), in particolare per gli argomenti che indicano con "...". Questo rimanda alla parte corrispondente della documentazione per .jcall (https://www.rforge.net/doc/packages/rJava/html/jcall.html), quando poi viene spiegato il requisito per chiamare .jcast (https://www.rforge.net/doc/packages/rJava/html/jcast.html) con alcuni esempi.

L'errore che hai ottenuto java.lang.NoSuchMethodError: <init> ti diceva che la JVM non riusciva a trovare il costruttore che hai chiamato. Questo era un aspetto misterioso nell'esempio che hai postato nei commenti. (Potrebbe essere utile modificare la tua domanda, a proposito, e includere quelle informazioni lì per i posteri.) Il codice ha certamente un aspetto corretto e, conoscendo Java, mi aspettavo intuitivamente che l'interfaccia rispettasse il polimorfismo di Java. Dato che (per qualsiasi motivo), l'interfaccia per R corrisponde alla corrispondenza di tipo "esatta" senza considerare l'ereditarietà, è chiaro che non troverà un costruttore a causa della ragione # 1 sopra.

Infine, in realtà non ho incontrato nessuna classe Java che utilizza i generici nella mia esplorazione limitata di Tetrad. A quanto pare, questa era una vera e propria falsa pista. Se dovesse verificarsi un problema in futuro, probabilmente vorrai controllare "Cancella tipo" (https://docs.oracle.com/javase/tutorial/java/generics/erasure.html). Se si interfacciava tra Java e C, C++, Fortran, qualsiasi linguaggio che Java considera "nativo", si tratterebbe dei generici nel codice nativo trattando i moduli cancellati dal tipo. L'interfaccia rJava potrebbe essere diversa, dal momento che questo sembra ricadere nello stesso tipo generale di struttura che ti ha fatto inciampare nel tuo problema attuale. (Forse degno della sua generosità più tardi!)

+0

Grazie !! Questo risolve il problema che stavo affrontando e mi dà una migliore comprensione di rJava (e di Java stesso). Non sono sicuro di come modificare la domanda, perché non ho fatto la domanda originale e hai scoperto che si tratta di un problema completamente separato rispetto a quello che stavo affrontando. Forse dovrei fare una domanda in due parti? –