Domanda In cosa differiscono i generici Java dai modelli C ++? Perché non posso usare int come parametro?


Sto cercando di creare

ArrayList<int> myList = new ArrayList<int>();

in Java, ma non funziona.

Qualcuno può spiegare perché int come parametro tipo non funziona?
utilizzando Integer classe per int opere primitive, ma qualcuno può spiegare perché int non è accettato?

Versione Java 1.6


44
2018-06-15 13:32


origine


risposte:


I generici Java sono così diversi dai modelli C ++ che non ho intenzione di provare ad elencare qui le differenze. (Vedere Quali sono le differenze tra i tipi "generici" in C ++ e Java? per ulteriori dettagli.)

In questo caso particolare, il problema è che non puoi usare le primitive come parametri di tipo generico (vedi JLS §4.5.1: "Gli argomenti Type possono essere sia tipi di riferimento che caratteri jolly.").

Tuttavia, a causa dell'autoboxing, puoi fare cose come:

List<Integer> ints = new ArrayList<Integer>();
ints.add(3); // 3 is autoboxed into Integer.valueOf(3)

In tal modo rimuove parte del dolore. Sicuramente fa male l'efficienza del runtime, però.


60
2018-06-15 13:36



La ragione per cui int non funziona è che non è possibile utilizzare i tipi primitivi come parametri generici in Java.

Per quanto riguarda la tua domanda, in che modo i modelli C ++ sono diversi dai generici di Java, la risposta è ... davvero molto diversa. Sono essenzialmente due approcci completamente diversi per implementare un simile effetto finale.

Java tende a concentrarsi sulla definizione del generico. Questa è la validità della definizione generica viene verificata solo considerando il codice nel generico. Se i parametri non sono adeguatamente vincolati, alcune azioni non possono essere eseguite su di essi. Il tipo effettivo con cui viene eventualmente invocato non viene considerato.

Il C ++ è il contrario. Solo la verifica minima viene eseguita sul modello stesso. Deve essere solo parsabile per essere considerato valido. L'effettiva correttezza della definizione viene eseguita nel punto in cui viene utilizzato il modello.


24
2018-06-15 13:44



Sono concetti molto diversi, che possono essere utilizzati per eseguire alcuni, ma non tutti gli stessi compiti. Come detto nelle altre risposte, ci vorrebbe un bel po 'per esaminare tutte le differenze, ma ecco quello che vedo come i tratti generali.

I generici consentono i contenitori polimorfici di runtime attraverso una singola istanza di un contenitore generico. In Java, tutti gli oggetti (non primitivi) sono riferimenti e tutti i riferimenti hanno la stessa dimensione (e alcuni hanno la stessa interfaccia) e quindi possono essere gestiti dal bytecode. Tuttavia, un'implicazione necessaria di avere solo un'istanza del codice byte è di tipo eraser; non è possibile stabilire con quale classe il contenitore è stato istanziato. Questo non funzionerebbe in c ++ a causa di un modello di oggetti fondamentalmente diverso, in cui gli oggetti non sono sempre riferimenti.

I modelli consentono di ottenere contenitori polimorfici in fase di compilazione attraverso più istanze (oltre alla metaprogrammazione del modello fornendo un linguaggio (attualmente debolmente tipizzato) sul sistema di tipo c ++). Ciò consente specializzazioni per determinati tipi, mentre il lato negativo è potenzialmente "code bloat" dal richiedere più di una istanza compilata.

I modelli sono più potenti dei generici; il primo è effettivamente un altro linguaggio incorporato in c ++, mentre per quanto ne so, quest'ultimo è utile solo nei contenitori


8
2018-06-15 15:53



questo perché int è un primitivo, è un problema conosciuto.

Se lo volessi davvero, puoi sottoclasse / scrivi la tua collezione che può farlo.


3
2018-06-15 13:37



Non è possibile utilizzare le primitive come parametri di tipo in Java. I generici di Java valgono attraverso la cancellazione dei caratteri, il che significa che il compilatore controlla che stai usando i tipi come li hai definiti, ma alla compilazione, tutto viene trattato come un oggetto. Poiché int e altri primitivi non sono oggetti, non possono essere utilizzati. Invece, usare Integer.


2
2018-06-15 13:36



Puoi provare TIntArraList da GNU Trove che agirà come un ArrayList di valori int.


1
2018-06-16 20:32



La principale differenza sta nel modo in cui vengono implementate, ma i loro nomi descrivono accuratamente la loro implementazione.

I modelli si comportano come modelli. Quindi, se scrivi:

template<typename T>
void f(T s)
{
    std::cout << s << '\n';
}

...
int x = 0;
f(x);
...

Il compilatore applica il modello, quindi nel compilatore finale considera il codice come:

void f_generated_with_int(int s)
{
    std::cout << s << '\n';
}

...
int x = 0;
f_generated_with_int(x);
...

Quindi, per ogni tipo che è usato per chiamare f un nuovo codice è "generato".

D'altra parte, i generici sono solo digitati, ma poi vengono cancellate tutte le informazioni sul tipo. Quindi, se scrivi:

class X<T> {
    private T x;

    public T getX() { return x; }
    public void setX(T x) { this.x = x; }
}

...
Foo foo = new Foo();
X<Foo> x = new X<>();
x.setX(foo);
foo = x.getX();
...

Java lo compila come:

class X {
    private Object x;

    public Object getX() { return x; }
    public void setX(Object x) { this.x = x; }
}

...
Foo foo = new Foo();
X x = new X();
x.setX(foo);
foo = (Foo)x.getX();
...

Alla fine:

  • i modelli richiedono l'istanza di ogni chiamata alla funzione basata su modelli (nella compilazione di ogni file .cpp), quindi i modelli sono più lenti da compilare
  • con i generici non puoi usare i primitivi, perché non lo sono Object, quindi i generici sono meno versatili

1
2018-03-03 14:01