java tipo - Perché le persone usano ancora i tipi primitivi in Java?




10 Answers

In Java efficace di Joshua Bloch, elemento 5: "Evita di creare oggetti non necessari", inserisce il seguente esempio di codice:

public static void main(String[] args) {
    Long sum = 0L; // uses Long, not long
    for (long i = 0; i <= Integer.MAX_VALUE; i++) {
        sum += i;
    }
    System.out.println(sum);
}

e ci vogliono 43 secondi per correre. Portare il Lungo nel primitivo lo porta a 6,8 secondi ... Se questo è un indizio del perché usiamo le primitive.

Anche la mancanza di uguaglianza dei valori nativi è una preoccupazione ( .equals() è piuttosto prolissa rispetto a == )

per biziclop:

class Biziclop {

    public static void main(String[] args) {
        System.out.println(new Integer(5) == new Integer(5));
        System.out.println(new Integer(500) == new Integer(500));

        System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
        System.out.println(Integer.valueOf(500) == Integer.valueOf(500));
    }
}

Risultati in:

false
false
true
false

EDIT Perché (3) restituisce true e (4) restituisce false ?

Perché sono due oggetti diversi. I 256 interi più vicini allo zero [-128; 127] sono memorizzati nella cache dalla JVM, quindi restituiscono lo stesso oggetto per quelli. Oltre questo intervallo, tuttavia, non vengono memorizzati nella cache, quindi viene creato un nuovo oggetto. Per rendere le cose più complicate, il JLS richiede che vengano salvati almeno 256 flyweights. Gli implementatori di JVM possono aggiungerne altri se desiderano, il che significa che potrebbero essere eseguiti su un sistema in cui i 1024 più vicini vengono memorizzati nella cache e tutti restituiscono true ... #awkward

byte variabili

Dal momento che Java 5, abbiamo avuto boxing / unboxing di tipi primitivi in ​​modo che int sia wrapper per essere java.lang.Integer , e così e così via.

Ultimamente vedo molti nuovi progetti Java (che richiedono sicuramente un JRE di almeno la versione 5, se non 6) che usano int piuttosto che java.lang.Integer , sebbene sia molto più comodo usare quest'ultimo, dato che ha alcuni metodi di supporto per la conversione in valori long et al.

Perché alcuni usano ancora i tipi primitivi in ​​Java? C'è qualche vantaggio tangibile?




Tipi primitivi:

int x = 1000;
int y = 1000;

Ora valuta:

x == y

È true Difficilmente sorprendente. Ora prova i tipi in scatola:

Integer x = 1000;
Integer y = 1000;

Ora valuta:

x == y

È false . Probabilmente. Dipende dal runtime. Questa è una ragione sufficiente?




Oltre alle prestazioni e ai problemi di memoria, mi piacerebbe venire fuori un altro problema: l' interfaccia List sarebbe stata interrotta senza int .
Il problema è il metodo overload remove() ( remove(int) vs. remove(Object) ). remove(Integer) risolverà sempre il richiamo di quest'ultimo, quindi non è possibile rimuovere un elemento per indice.

D'altra parte, vi è un trabocchetto quando si tenta di aggiungere e rimuovere un int :

final int i = 42;
final List<Integer> list = new ArrayList<Integer>();
list.add(i); // add(Object)
list.remove(i); // remove(int) - Ouch!



I tipi primitivi sono molto più veloci:

int i;
i++;

L'intero (tutti i numeri e anche una stringa) è un tipo immutabile : una volta creato non può essere modificato. Se fossi Integer, allora i++ creerebbe un nuovo oggetto Integer, molto più costoso in termini di memoria e processore.




A proposito, Smalltalk ha solo oggetti (non primitivi), e tuttavia hanno ottimizzato i loro piccoli numeri interi (usando non tutti i 32 bit, solo 27 o simili) per non allocare alcuno spazio di heap, ma semplicemente usano uno schema di bit speciale. Anche altri oggetti comuni (true, false, null) avevano schemi di bit speciali qui.

Quindi, almeno sulle JVM a 64 bit (con uno spazio dei nomi puntatore a 64 bit) dovrebbe essere possibile non avere alcun oggetto di Intero, Carattere, Byte, Corto, Booleano, Float (e Piccolo lungo) affatto (a parte questi creati da new ...() esplicito new ...() ), solo modelli di bit speciali, che potrebbero essere manipolati dai normali operatori in modo abbastanza efficiente.




Un paio di ragioni per non liberarsi dei primitivi:

  • Compatibilità all'indietro.

Se è eliminato, qualsiasi vecchio programma non verrebbe nemmeno eseguito.

  • Riscrittura JVM.

L'intera JVM dovrebbe essere riscritta per supportare questa nuova cosa.

  • Più grande spazio di memoria.

Dovresti memorizzare il valore e il riferimento, che utilizza più memoria. Se si dispone di una vasta gamma di byte, l'utilizzo di byte è significativamente inferiore rispetto all'utilizzo di Byte .

  • Problemi con puntatori nulli.

Se dichiaro che int i facendo cose con i avrei riscontrato alcun problema, ma dichiarare Integer i e poi fare lo stesso risulterebbe in un NPE.

  • Problemi di uguaglianza.

Considera questo codice:

Integer i1 = 5;
Integer i2 = 5;

i1 == i2; // Currently would be false.

Sarebbe falso Gli operatori dovrebbero essere sovraccaricati e ciò comporterebbe una grande riscrittura delle cose.

  • Lento

I wrapper di oggetti sono molto più lenti delle loro controparti primitive.




Gli oggetti sono molto più pesanti dei tipi primitivi, quindi i tipi primitivi sono molto più efficienti rispetto alle istanze delle classi wrapper.

I tipi primitivi sono molto semplici: per esempio un int è 32 bit e occupa esattamente 32 bit in memoria e può essere manipolato direttamente. Un oggetto intero è un oggetto completo, che (come qualsiasi oggetto) deve essere memorizzato nell'heap e accessibile solo tramite un riferimento (puntatore) ad esso. Molto probabilmente richiede anche più di 32 bit (4 byte) di memoria.

Detto questo, il fatto che Java abbia una distinzione tra tipi primitivi e non primitivi è anche un segno dell'età del linguaggio di programmazione Java. I nuovi linguaggi di programmazione non hanno questa distinzione; il compilatore di un tale linguaggio è abbastanza intelligente da capire da solo se si utilizzano valori semplici o oggetti più complessi.

Ad esempio, in Scala non ci sono tipi primitivi; c'è una classe Int per interi, e una Int è un oggetto reale (che puoi usare su metodi, ecc.). Quando il compilatore compila il tuo codice, utilizza inti primitivi dietro le quinte, quindi usare un Int è altrettanto efficace quanto usare un int primitivo in Java.




I tipi primitivi presentano molti vantaggi: - Codice più semplice da scrivere - Le prestazioni sono migliori poiché non si crea un'istanza di un oggetto per la variabile - Dal momento che non rappresentano un riferimento a un oggetto, non è necessario controllare i valori null - Utilizzare i tipi primitivi a meno che bisogno di sfruttare le funzionalità di boxe.




Sono d'accordo con le risposte precedenti, l'uso di oggetti wrapper primitivi può essere costoso. Tuttavia, se le prestazioni non sono critiche nella tua applicazione, eviti gli overflow quando usi gli oggetti. Per esempio:

long bigNumber = Integer.MAX_VALUE + 2;

Il valore di bigNumber è -2147483647 e ci si aspetterebbe che sia 2147483649. È un errore nel codice che verrebbe risolto eseguendo:

long bigNumber = Integer.MAX_VALUE + 2l; // note that '2' is a long now.

E bigNumber sarebbe 2147483649. Questi tipi di bug a volte sono facili da perdere e possono portare a comportamenti o vulnerabilità sconosciuti (vedi CWE-190 ).

Se si utilizzano oggetti wrapper, il codice equivalente non verrà compilato.

Long bigNumber = Integer.MAX_VALUE + 2; // Not compiling

Quindi è più facile fermare questo tipo di problemi usando gli oggetti wrapper primitivi.

La tua domanda ha già una risposta così, che rispondo solo per aggiungere un po 'più di informazioni non menzionate prima.




Perché JAVA esegue tutte le operazioni matematiche in tipi primitivi. Considera questo esempio:

public static int sumEven(List<Integer> li) {
    int sum = 0;
    for (Integer i: li)
        if (i % 2 == 0)
            sum += i;
        return sum;
}

Qui, le operazioni Promemoria e Unario Plus non possono essere applicate al tipo Integer (Riferimento), il compilatore esegue l'unboxing e esegue le operazioni.

Quindi, assicurati quante operazioni di autoboxing e unboxing si verificano nel programma java. Poiché, ci vuole tempo per eseguire queste operazioni.

Generalmente, è meglio mantenere argomenti di tipo Reference e result di tipo primitivo.




Related

java primitive primitive-types autoboxing jdk1.5