Primi passi in Java

Venerdì, 1 Ottobre 2004

OBIETTIVI DELLA LEZIONE

In questa lezione impareremo a conoscere:

  1. Variabili e tipi di dato
  2. Operatori
  3. Strutture di controllo: IF

Alla fine della lezione saremo in grado di scrivere autonomamente la nostra prima semplice classe Java.

Dati

Un "dato" è una quantità minimale di informazione che vogliamo elaborare con il nostro programma. Può essere il soldo del nostro conto corrente, il numero di amici che abbiamo invitato alla nostra festa o il colore del gatto del vicino.

Come nell'algebra e in altri linguaggi di programmazione, anche in Java chiamiamo variabile il nome simbolico che assegnamo ad un determinato valore. Le variabili vengono manipolate con degli operatori che ne modificano il valore. Frasi che coinvolgono variabili ed operatori, vengono chiamate espressioni.

Tipi di dati

Supponiamo di dover preparare un modulo cartaceo da compilare per un sondaggio; (l'utente compilerà il modulo con una penna, nessun computer). L'utente deve inserire il proprio sesso, l'età e la marca delle caramelle preferite. Probabilemente prevederemmo una cosa del genere:

 Sesso: _
 Età: __
 Marca caramelle preferite: ____________________

Infatti, per il sesso basta inserire un carattere, M o F, due numeri per l'età e per la marca preferita, che non conosciamo a priori, lasciamo 20 spazi vuoti. Ciascun dato occuperà un certo "spazio" sul foglio, ad esempio la variabile "Sesso" occuperà uno spazio.

In un programma Java, come del resto in ogni linguaggio di programmazione, i dati vengono immagazzinati in memoria da qualche parte (per oggi non ci preoccuperemo di capire dove). Per ogni variabile viene predisposto lo spazio opportuno: come sul foglio venivano predisposti degli spazi per le lettere scritte a penna, allo stesso modo nella memoria del calcolatore viene riservato un numero di byte adeguato.

Per poter fare questo, Java richiede che venga specificato sempre il tipo di dato che vogliamo sia contenuto in una variabile. Ad esempio:

    int questo;
    short mese;

Il tipo di dato non può essere cambiato nel corso del programma. Java è un linguaggio fortemente tipizzato (non lo sarà affatto il PHP).

Una variabile può essere:

Tipi di dati primitivi

In Java, i tipi di dati primitivi sono i mattoni base a partire dai quali vengono costruiti tutti gli altri oggetti. NON sono oggetti. Sono stati pensati a partire da quelli definiti dal C, con alcuni miglioramenti e semplificazioni efficaci. Eccoli:

Tipo Valore Default Occupa Intervallo
boolean true, false false 1 bit
char carattere Unicode \u0000 2 bytes da \u0000 a \uFFFF
byte intero (con segno) 0 1 byte da -128 a 127
short intero (con segno) 0 2 bytes da -32768 a 32767
int intero (con segno) 0 4 bytes da -2147483648 a 2147483647
long intero (con segno) 0 8 bytes da -9223372036854775808 a 9223372036854775807
float numeri a virgola mobile (IEEE 754) 0.0 4 bytes da ±1.4E-45 a ±3.4028235E+38
double numeri a virgola mobile (IEEE 754) 0.0 8 bytes da ±4,9E-324 a ±1.7976931348623157E+308

Valori logici

In Java assumono i valori true o false e NON sono dei numeri interi ne possono essere convertiti in numeri interi come succede in C o C++.

Interi

I numeri interi sono tutti con il segno. NON esistono i numeri unsigned come in C. Inoltre hanno una dimensione che è fissata dal linguaggio (quella della tabella sopra) e non variabile con il tipo di architettura.

I numeri vengono rappresentati in base 2 e non in base decimale. Questo perché, come ben sapete, le memorie sono bistato e possono solo memorizzare due valori, che per convenzione si assumono essere 0 o 1.

Ripasso

In base 2 ci sono solo due simboli a disposizione, ad esempio, 7 diventa 111 mentre 37 diventa 100101. In base 16 (esadecimale) ci sono invece 16 simboli a disposizione e per convenzione si utilizzano le lettere da A a E per rappresentare i numeri da 10 a 15. Ad esempio, 37 diventerebbe 25.

Cosa rappresenta il numero 155 in base 10? 155 = 1 * 102 + 5 * 101 + 5 * 100. Cioè ogni cifra ha un valore in base alla posizione (infatti si chiama notazione posizionale e non è l'unico modo di rappresentare i numeri, basti ad esempio pensare alla rappresentazione romana in cui 155 = CLV).

Come si converte un numero decimale in un altra base? Lo si deve dividere ripetutamente per la base fino ad ottenere 0. I resti delle divisioni intere, letti dall'ultimo al primo, sono le cifre del numero convertito.

Esempio: convertiamo 155 in base 2.

        155/2 = 77/2 = 38/2 = 19/2 = 9/2 = 4/2 = 2/2 = 1/2 = 0
          1      1      0      1     1     0     0     1
        <---Leggiamo i resti in questa direzione -----
        10011011
        

Esempio: convertiamo 155 in base 16.

        155/16 = 9/16 = 0
         11      9
        <---Leggiamo i resti in questa direzione -----
        9B
        

Per convertire da base 2 o 16 a base decimale, dobbiamo semplicemente multiplicare ciascuna cifra del numero per il suo valore posizionale.

Esempio: convertiamo 10011011 in base 10.

        10011011 = 1*2^7 + 0*2^6 + 0*2^5 + 1*2^4 + 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0 =
                 = 1*128 + 0* 64 + 0* 32 + 1* 16 + 1*  8 + 0*  4 + 1*  2 + 1*  1 =
                 =   128 +     0 +     0 +    16 +     8 +     0 +     2 +     1 =
                 = 155
        (il simbolo ^ indica qui l'elevamento a potenza, ma non è un operatore JAVA!)
        

La base 16 è un multiplo della base 2. Dato un numero in base due, per passare ad un numero in base 16 basta convertirlo 4 cifre alla volta.

Esempio: convertiamo 10011011 in base 16.

        10011011 --> 1001 e 1011
                     8+0+0+1 e 8+0+2+1
                     9 e B
                     9B
                     9B
        

I numeri negativi vengono rappresentati in complemento a 2. Per prima cosa ricordiamoci che il complemento a 1 di un numero si costruisce invertendo tutti i bit della sua rappresentazione binaria.

Esempio: calcoliamo il complemento a 1 dell'intero 155.

        155 è un intero, quindi sarà contenuto in 32 bits:
        00000000 00000000 00000000 10011011
        invertiamo tutti i bits
        11111111 11111111 11111111 01100100
        

Il complento a 2 del numero A si ottiene sommando 1 al suo complemento a 1 (che in Java è l'operatore ~ come in C).

Esempio: calcoliamo il complemento a 2 di 155.

        ~155 + 1 =
                   11111111 11111111 11111111 01100100 +
                   00000000 00000000 00000000 00000001 =

                   11111111 11111111 11111111 01100101
        

La notazione in complemento a 2 si utilizza in modo che A+(-A)=0.

Esempio: calcoliamo 155 + (-155).

         155 -->   00000000 00000000 00000000 10011011 +
        -155 -->   11111111 11111111 11111111 01100101 +

                   00000000 00000000 00000000 00000000
        

I numeri negativi in Java sono rappresentati in complemento a due. Attenzione alla circolarità indotta dalla rappresentazione: se allo short A = 32767 aggiungiamo 1 otteniamo -1!

class EsempioCircolarita {
  public static void main(String[] args) {
    short a = 32767;
    a += 1;
    System.out.println(a);
    short b = -32768;
    b -= 1;
    System.out.println(b);
  }
}
>java EsempioCircolarita
-32768
32767

Nei nostri programmi utilizzeremo solo numeri interi di tipo int e long, visto che per quanto ci riguarda possiamo fare a meno delle altre tipologie.

Numeri a virgola mobile

I numeri a virgola mobile sono una rappresentazione dei numeri razionali. NON sono un insieme denso cioè tra due numeri non è detto che ce ne sia un terzo né sono illimitati.

Durante il corso utilizzaremo solo numeri a virgola mobile di tipo double.

Caratteri

Ripasso

Nella memoria di un calcolatore possiamo memorizzare solo numeri binari. Di certo non possiamo memorizzare un segno grafico come un carattere. Lo stesso problema lo affrontarono coloro che organizzarono le trasmissioni telegrafiche: come trasmettere un messaggio con uno strumento in grado di trasmettere solo punti e linee? Ovviamente è necessaria una codifica: ad ogni carattere associamo un numero che trasmettiamo o, nel nostro caso, memorizziamo.

Una codifica che si affermò in modo pressoché universale fu quella standard ASCII, che comprendeva 128 caratteri (7 bits) tra cui alcuni caratteri di controllo che erano utilizzati per le trasmissioni e la gestione del terminale. 128 caratteri non sono molti ma erano sufficienti per codificare la lingua inglese che non usa le lettere accentate. La codifica ASCII è la seguente:

 NUL(  0)    SOH(  1)    STX(  2)    ETX(  3)
 EOT(  4)    ENQ(  5)    ACK(  6)    BEL(  7)
 BS (  8)    HT (  9)    NL ( 10)    VT ( 11)
 FF ( 12)    CR ( 13)    SO ( 14)    SI ( 15)
 DLE( 16)    DC1( 17)    DC2( 18)    DC3( 19)
 DC4( 20)    NAK( 21)    SYN( 22)    ETB( 23)
 CAN( 24)    EM ( 25)    SUB( 26)    ESC( 27)
 FS ( 28)    GS ( 29)    RS ( 30)    US ( 31)
 SP ( 32)     ! ( 33)     " ( 34)     # ( 35)
  $ ( 36)     % ( 37)     & ( 38)     ' ( 39)
  ( ( 40)     ) ( 41)     * ( 42)     + ( 43)
  , ( 44)     - ( 45)     . ( 46)     / ( 47)
  0 ( 48)     1 ( 49)     2 ( 50)     3 ( 51)
  4 ( 52)     5 ( 53)     6 ( 54)     7 ( 55)
  8 ( 56)     9 ( 57)     : ( 58)     ; ( 59)
  < ( 60)     = ( 61)     > ( 62)     ? ( 63)
  @ ( 64)     A ( 65)     B ( 66)     C ( 67)
  D ( 68)     E ( 69)     F ( 70)     G ( 71)
  H ( 72)     I ( 73)     J ( 74)     K ( 75)
  L ( 76)     M ( 77)     N ( 78)     O ( 79)
  P ( 80)     Q ( 81)     R ( 82)     S ( 83)
  T ( 84)     U ( 85)     V ( 86)     W ( 87)
  X ( 88)     Y ( 89)     Z ( 90)     [ ( 91)
  \ ( 92)     ] ( 93)     ^ ( 94)     _ ( 95)
  ` ( 96)     a ( 97)     b ( 98)     c ( 99)
  d (100)     e (101)     f (102)     g (103)
  h (104)     i (105)     j (106)     k (107)
  l (108)     m (109)     n (110)     o (111)
  p (112)     q (113)     r (114)     s (115)
  t (116)     u (117)     v (118)     w (119)
  x (120)     y (121)     z (122)     { (123)
  | (124)     } (125)     ~ (126)    DEL(127)

Per permettere la codifica di lingue che utilizzano molti caratteri accentati lo standard ASCII fu esteso a 8 bits in vari modi differenti. Microsoft per MSDOS introdusse le "code pages": i caratteri dal 128 al 255 erano diversi a seconda della code page scelta. Ad esempio, la code page inglese era la 437 mentre quella italiana la 850.

Ad un certo punto per evitare il dilagare di approcci differenti fu introdotto lo standard a 8 bits ISO 8859-1, chiamato anche ISO Latin1. La code page di MS Window nelle lingue occidentali è la 1252, compatibile con lo standard.

La differenza tra le code pages causa effetti deleteri quando si programma in linguaggi come il C. Ad esempio la lettera 'è' viene codificata con il codice 232 da MS Windows mentre lo stesso codice corrisponde alla lettera thorn maiuscola Þ (presente nell'alfabeto finlandese) nella console. Semplice no?

Fortunatamente queste sono complicazioni in estinzione. Per semplificare le comunicazioni nell'era dell'informatizzazione globale è stata introdotto una codifica detta UNICODE in cui si arrivano ad utilizzare fino a 32 bits per carattere: è possibile rappresentare anche tutti gli ideogrammi cinesi!

Compatibile con questa codifica è lo standard a 16 bits ISO/IEC 10646 utilizzato da Java.

I caratteri in Java sono codificati seguendo lo standard UNICODE a 16 bits, cioè per ciascun carattere sono utilizzati due bytes (NON uno come in C). Questo permette di includere pressoché qualunque tipo di carattere.

Per rappresentare una costante carattere la si deve includere tra due apici semplici. Per assegnare un carattere unicode ad una variabile si utilizza la forma \uXXXX dove XXXX è la codifica esadecimale. Comode sone le seguenze di escape, come in C:

\n a capo (LF)
\t tabulazione orizzonatale (HT)
\\ backslash \
\' apice '
\" virgolette doppie "

Esempi:

    char carattere = 'R';
    char carattere = '\n';
    char carattere = '\u05D0';    

Stringhe

Le stringhe NON sono un tipo di dato primitivo ma un oggetto della classe String. Mnemonicamente potete ricordare che String inizia con una maiuscola, come del resto tutte le classi, a differenza dei tipi primitivi che iniziano con una minuscola.

Le stringhe però a differenza di tutti gli altri oggetti possono essere inizializzate con una costante, come in C. Esempio:

    String frase = "Questa è una stringa";

Le stringhe non sono terminate da un carattere NULL come in C: non ci interessa come siano rappresentate nella memoria. Questo è un tipico della programmazione ad oggetti e si chiama "incapsulazione": nascondere i dettagli implementativi.

Casting

Il Java ha un controllo dei tipi molto più stringente che il C. Permette conversioni di tipo implicite SOLO quando è impossibile perdere informazioni. Altrimenti, se si vuole forzare la converisone di tipo dobbiamo forzarla, come in C, con un cast. Esempio:

    long numeroLungo = 35267;
    int numeroCorto;
    numeroCorto = (int)numeroLungo;

La seguente è la tabella delle conversioni implicite ammesse:

boolean byte short int long float double char
boolean - NO NO NO NO NO NO NO
byte NO - SI SI SI SI SI CAST
short NO CAST - SI SI SI SI CAST
int NO CAST CAST - SI SI SI CAST
long NO CAST CAST CAST - SI SI CAST
float NO CAST CAST CAST CAST - SI CAST
double NO CAST CAST CAST CAST CAST - CAST
char NO CAST CAST SI SI SI SI -

Operatori

Gli operatori Java coincidono pressoché con quelli C/C++.

Aritmetici

Somma (+), sottrazione (-), moltiplicazione (*), divisione (/) e resto della divisione intera (%). ATTENZIONE: se la divisione è fatta tra due interi NON produce un numero a virgola mobile!

Concatenamento stinghe

L'operatore + quando usato con due stringhe le concatena. Esempio:

    String nome = "Luigi" + " " + "Rossi";

Assegnamento

L'operatore di assegnamento è il segno di uguale (=). Come in C, la maggior parte degli operatori può essere combinata con l'operatore di assegnamento. Ad esempio, a += 3; corrisponde a a = a + 3;.

Relazionali

Uguale (==), diverso (!=), maggiore (>), maggiore e uguale (>=), minore (<) e minore e uguale (<=). Restituiscono il valore boolean true se la relazione è verificata, false altrimenti.

Commenti

In Java è possibile inserire commenti nel codice in tre modi. I primi deu sono identici a quelli previsti dal C++. Esempio:

  /* Questo è 
  un commento
  su 
  più righe. */
  
  // Questo è un commento a singola riga

Il terzo modo serve per specificare dettagli di un programma agli altri programmatori (o anche a noi stessi). Lo vederemo più avanti.

Istruzioni e blocchi

Una istruzione in Java coincide con un comando eseguito dalla JVM. Un blocco è un insieme di istruzioni racchiuso tra parentesi graffe. E' possibile dichiarare delle variabili locali all'interno di in blocco di istruzioni, e non è necessario farlo all'inizio come in C89. I blocchi possono essere annidati a piacere: le variabili locali sono visibili dal punto della loro dichiarazione fino alla fine del blocco cui appartengono, (quindi anche nei sottoblocchi). (Queste sono chiamate in genere regole di scopo o di visibilità).

  int a = 1;
  { 
    int b;
    b = a; // b diventa 1
  } // qui la variabile b cessa di esistere
 

Una sequenza è invece una banale successione di istruzioni.

Strutture di controllo del flusso 1/4

Strutture condizionali: if

Composta da UNA espressione e UNO/DUE/TRE blocchi di codice (chiamati i "rami" dell' if)

if (condizioneLogica)
  istruzione1;
 

oppure

if (condizioneLogica)
  istruzione1;
else 
  istruzione2;
 

oppure

if (condizioneLogica1)
  istruzione1;
else if (condizioneLogica2)
  istruzione2;
else if (condizioneLogica3)
  istruzione3;
else 
  istruzione4;
 

Ciuscuna istruzione può essere costituita da un istruzione singola o da un blocco.

Lab

Esercizio 0

Studiare, compilare ed eseguire il seguente programma Java. Come si chiama il nome del file in cui deve essere contenuto?

import javax.swing.*;

class Somma {
  public static void main(String[] args) {
    String stringaInput;
    int primoNumero, secondoNumero;
    
    stringaInput = JOptionPane.showInputDialog("Inserisci il primo numero");
    primoNumero = Integer.parseInt(stringaInput);
    
    stringaInput = JOptionPane.showInputDialog("Inserisci il secondo numero");
    secondoNumero = Integer.parseInt(stringaInput);
    
    JOptionPane.showMessageDialog(null, "La somma dei due numeri è " + 
      (primoNumero+secondoNumero));
    
    System.exit(0);
  }
}

Esercizio 1

Dopo aver studiato l'esercizio 0, utilizzando le funzioni di input/output della classe JOptionPane, scrivere la classe Java Radice che chieda all'utente un numero a virgola mobile e restituisca all'utente la sua radice quadrata.

Suggerimenti: usate la funzione Double.parseDouble(String x) per ottenere un double da una stringa di input; utilizzate la funzione Math.sqrt(double x) per ottenere la radice quadrata.

Esercizio 2

Dopo aver svolto l'esercizio 1, scrivere la classe Java EquazioneSecondoGrado che risolva una equazione di secondo grado.

©2004 Roberto Sassi