• Non ci sono risultati.

Caratteri in una stringa

N/A
N/A
Protected

Academic year: 2021

Condividi "Caratteri in una stringa"

Copied!
78
0
0

Testo completo

(1)

1

Il tipo di dati char (capitolo 4)

SETTIMANA 3

Caratteri in una stringa

Sappiamo già come estrarre sottostringhe da  una stringa, con il metodo substring

A volte è necessario estrarre ed elaborare  sottostringhe di dimensioni minime, cioè di  lunghezza unitaria

una stringa di lunghezza unitaria contiene un solo  carattere, che può essere memorizzato in una  variabile di tipo char anziché in una stringa

 il tipo char in Java è un tipo di dato 

fondamentale come i tipi di dati numerici ed il tipo  boolean, cioè non è una classe

(2)

3

Caratteri in una stringa

La presenza del tipo di dati char non è strettamente  necessaria in Java (ed è anche per questo motivo che  non l’avevamo ancora studiato)

infatti, ogni elaborazione che può essere fatta su 

variabili di tipo char potrebbe essere fatta su stringhe di  lunghezza unitaria

L’uso del tipo char per memorizzare stringhe di lunghezza  unitaria è però importante, perché

una variabile di tipo char occupa meno spazio in memoria  di una stringa di lunghezza unitaria

le elaborazioni su variabili di tipo char sono più veloci

Caratteri in una stringa

Il metodo charAt della classe String restituisce il  singolo carattere che si trova nella posizione indicata  dal parametro ricevuto

 la convenzione sulla numerazione delle posizioni in  una stringa è la stessa usata dal metodo substring

Una struttura di controllo che si usa spesso è  l’elaborazione di tutti i caratteri di una stringa

String s = "John";

char ch = s.charAt(2); // ch contiene 'h'

String s = "John";

for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i);

// elabora ch }

(3)

5

Elaborazioni su variabili char

Come si può elaborare una variabile di tipo char?

Una variabile di tipo char può anche essere confrontata  con una costante di tipo carattere

una costante di tipo carattere è un singolo carattere  racchiuso tra singoli apici (“apostrofo”)

Il carattere può anche essere una “sequenza di escape”

Una variabile carattere può essere stampata passandola  a System.out.print o System.out.println

char ch = 'x';

char ch = '\u00E9'; // carattere 'è'

char nl = '\n'; // carattere di "andata a capo"

char ch = 'x';

System.out.println(ch); // stampa 'x' e va a capo

Caratteri e l'operatore +

Un char può essere concatenato ad una stringa con 

l’operatore di concatenazione + (viene convertito in stringa,  con le stesse regole della conversione dei tipi numerici)

Se invece i due operandi di + sono entrambi caratteri

 Vengono automaticamente convertiti (“promossi”) in int

L'operatore + indica una normale somma tra interi

char a = 'a';

char b = 'b';

int intc = a + b;

char c = (char)(a + b);

System.out.println(“intc: ” + intc);

System.out.println(“c: “ + c);

intc: 195 c: Ã

(4)

7

Caratteri speciali e  sequenze di “escape”

Sequenze di “escape”

Proviamo a stampare una stringa che contiene delle  virgolette

Il compilatore identifica le seconde virgolette come la fine  della prima stringa "Hello, ", ma poi non capisce il  significato della parola World

Basta inserire una barra rovesciata \ (backslash) prima  delle virgolette all’interno della stringa

// NON FUNZIONA!

System.out.println("Hello, "World"!");

Hello, "World"!

System.out.println("Hello, \"World\"!");

(5)

9

Sequenze di “escape”

Il carattere backslash all’interno di una stringa non  rappresenta se stesso, ma si usa per codificare altri 

caratteri che sarebbe difficile inserire in una stringa, per  vari motivi (sequenza di escape)

Allora, come si fa ad inserire veramente un carattere  backslash in una stringa?

si usa la sequenza di escape \\

// FUNZIONA!

System.out.println("Hello, \"World\"!");

System.out.println("File C:\\autoexec.bat");

File C:\autoexec.bat

Sequenze di “escape”

Un’altra sequenza di escape che si usa è \n, che  rappresenta il carattere di “nuova riga” o “andare a  capo”

Le sequenze di escape si usano anche per inserire  caratteri di lingue straniere o simboli che non si  trovano sulla tastiera

System.out.println("*\n**\n***");

***

***

System.out.println("*");

System.out.println("**");

System.out.println("***");

(6)

11

Sequenze di “escape”

Ad esempio, per scrivere parole italiane con lettere  accentate senza avere a disposizione una tastiera  italiana

Queste sequenze di escape utilizzano la codifica  standard Unicode ­ 

http://www.unicode.org 

per 

rappresentare i caratteri di tutti gli alfabeti del mondo  con 4 cifre esadecimali (codifica a 16 bit, 65536  simboli diversi)

System.out.println("Perch

\u00E9

?");

Perché?

Escape e caratteri di controllo

Alcune sequenze di escape possono essere usate per  rappresentare dei caratteri di controllo

Ovvero caratteri Unicode che non rappresentano  simboli scritti

 Ma che fanno parte integrante di un flusso di testo,  come tutti gli altri caratteri

SEQ.ESCAPE NOME COD.UNICODE

\n newline \u000A

\t tab \u0009

\b backspace \u0008

\r return \u000D

\f formfeed \u000C

(7)

13

Caratteri di controllo

I primi 32 caratteri nella codifica Unicode sono tutti  caratteri di controllo

 Il cosiddetto insieme C0 di ASCII (e Unicode)

 Per chi e' interessato

http://en.wikipedia.org/wiki/C0_and_C1_control_codes

http://en.wikipedia.org/wiki/Control_character

Vedremo altri importanti caratteri di controllo

ETX (End­of­TeXt), immesso da tastiera con <CTRL>+C

usato per interrompere l'esecuzione di un programma

EOT (End­Of­Transmission, <CTRL>+D) e SUB  (SUBstitute, <CTRL>+Z)

Usati per segnalare la fine dell'input, ad esempio di un file 

Formattazione di numeri:

il metodo printf

(8)

15

Formattazione di numeri

Non sempre il formato standard per stampare numeri  corrisponde ai nostri desideri

Ci piacerebbe di più visualizzare i numeri

 Con due cifre decimali

 Incolonnati

double total = 3.50;

final double TAX_RATE = 8.5; // aliquota d’imposta in percentuale

double tax = total * TAX_RATE / 100;

System.out.println(“Total: “ + total);

System.out.println(“Tax: “ + tax); Total: 3.5 Tax: 0.2975

Total: 3.50 Tax: 0.30

Formattazione di numeri

Java fornisce il metodo printf, che ha più parametri  espliciti

 Il primo parametro è una stringa di formato che  contiene caratteri da stampare e specificatori di  formato

Ogni specificatore di formato comincia con il carattere %

 I parametri successivi sono i valori da visualizzare  secondo i formati specificati

 Produce:

System.out.printf(“Total:%5.2f”, total) Total: 3.50

Spazio

(9)

17

Formattazione di numeri

Tipi di formato e modificatori di formato:

Caratteri di fine riga

Diversi sistemi operativi “capiscono” diversi caratteri di  fine riga

 Sistemi Unix usano il carattere newline (o line­feed): \n

 DOS usa la sequenza carriagereturn­newline: \r\n

Per essere sicuri che la fine della riga sia riconosciuta  da qualsiasi sistema operativo possiamo usare il 

metodo printf con il formato %n

 produce Total: 3.50

System.out.printf(“Total:%5.2f%n”, total) Nuova riga

(10)

19

Ricevere dati in ingresso

I dati in ingresso ai programmi

I programmi visti finora non sono molto utili, visto  che eseguono sempre la stessa elaborazione  ad ogni esecuzione

Il programma Coins1 rappresenta sempre il  medesimo borsellino…

 se si vuole che calcoli il valore contenuto in un  diverso borsellino, è necessario modificare il  codice sorgente (in particolare, le inizializzazioni  delle variabili) e compilarlo di nuovo

I programmi utili hanno bisogno di ricevere dati  in ingresso dall’utente

(11)

21

L’input standard dei programmi

Il modo più semplice e immediato per fornire dati  in ingresso ad un programma consiste 

nell’utilizzo della tastiera

 altri metodi fanno uso del mouse, del microfono…

Abbiamo visto che tutti i programmi Java hanno  accesso al proprio output standard, tramite  l’oggetto System.out di tipo PrintStream

Analogamente, l’interprete Java mette a  disposizione dei programmi in esecuzione il 

proprio input standard (flusso di input), tramite  l’oggetto System.in di tipo InputStream

La classe Scanner

Sfortunatamente, la classe InputStream non  possiede metodi comodi per la ricezione di dati  numerici e stringhe

PrintStream ha invece il comodissimo metodo print

Per ovviare a questo inconveniente, Java 5.0 ha  introdotto la classe Scanner

Un oggetto di tipo Scanner consente di leggere da  qualsiasi flusso di ingresso (ad es. un file)

 Noi cominciamo ad usarlo per leggere dati in ingresso  da tastiera ricevuti tramite l'oggetto System.in

(12)

23

Leggere l’input con la  classe Scanner

Scanner in = new Scanner(System.in);

Usare la classe Scanner

Per leggere dallo standar input bisogna creare un oggetto di tipo  Scanner, usando la sintassi consueta

Il parametro esplicito del costruttore di Scanner è System.in

L'oggetto in di tipo Scanner è “agganciato” allo standard  input

Dato che la classe Scanner non fa parte del pacchetto 

java.lang, ma del pacchetto java.util, è necessario importare  esplicitamente la classe all'interno del file java che ne fa uso 

Quando non si usa piu’ l’oggetto di classe Scanner e’ bene  chiuderlo:

import java.util.Scanner;

in.close();

Sono due oggetti diversi!!

(13)

25

I metodi nextInt e nextDouble 

Come si fa ad acquisire valori numerici da standard input?

Numero intero: metodo int nextInt()

Numero in virgola mobile: metodo double nextDouble()

Durante l’esecuzione del metodo (nextInt o nextDouble) il  programma si ferma ed attende l’introduzione dell’input da  tastiera, che termina quando l’utente batte il tasto Invio

nextInt restituisce un valore numerico di tipo int

NextDouble restituisce un valore numerico di tipo double

cosa succede se l’utente non digita un numero intero (o un  numero double) sulla tastiera ?? Provare!!

int number = in.nextInt();

double number = in.nextDouble();

Esempio

import java.util.Scanner;

public class Coins4

{ public static void main(String[] args) { Scanner in = new Scanner(System.in);

System.out.println("Quante lire?");

int lit = in.nextInt();

System.out.println("Quanti euro?");

double euro = in.nextDouble();

System.out.print("Valore totale in euro ");

System.out.println(euro + lit / 1936.27);

} }

(14)

27

I metodi next e nextLine

Come si fa ad acquisire stringhe da standard input?

Parola 

 ovvero una stringa delimitata dai caratteri di spaziatura  space (SP), tab (\t), newline (\n), carriage­return (\r)

metodo String next()

Riga

(ovvero una stringa delimitata dai caratteri \n o \r): 

metodo String nextLine(): 

String city = in.nextLine();

String state = in.next();

Esempio

import java.util.Scanner;

public class MakePassword2

{ public static void main(String[] args) { Scanner in = new Scanner(System.in);

System.out.println("Inserire il nome");

String firstName = in.nextLine();

System.out.println("Inserire il cognome");

String lastName = in.nextLine();

System.out.println("Inserire l’eta’");

int age = in.nextInt();

String initials = firstName.substring(0, 1) + lastName.substring(0, 1);

String pw = initials.toLowerCase() + age;

System.out.println("La password e’ " + pw);

} }

(15)

29

Scanner e localizzazione

La classe Scanner prevede la possibilità di riconoscere  numeri formattati secondo diverse “usanze locali”

 Nel corso noi useremo la convenzione anglosassone che  prevede l’uso del carattere di separazione ‘.’ tra parte 

intera e parte frazionaria nei numeri in virgola mobile

Per definire un oggetto Scanner che rispetta questa 

convenzione dovremo importare anche la classe Locale  e scrivere

import java.util.Scanner;

import java.util.Locale;

...

Scanner in = new Scanner(System.in);

in.useLocale(Locale.US);

...

È tutto chiaro? …

1. Perché non si possono leggere dati in ingresso  direttamente tramite System.in ?

2. Se in è un oggetto di tipo Scanner che legge da  System.in  e il nostro programma invoca

String name = in.next();

Qual è il valore di name se l’utente digita la  seguente stringa?

John Q. Public

(16)

31

Realizzare classi

(Capitolo 3)

(17)

33

Scatole nere

Per molti guidatori

 Un’automobile è una scatola nera

 Non sanno come funziona

 Ma sanno come usarla

Un ingegnere meccanico sa

progettare una automobile ma non i moduli di controllo elettronico

 Non ne conosce il funzionamento interno

 Ma sa come usarli

Scatole nere danno luogo ad incapsulamento

 I dettagli non importanti vengono nascosti

 Ma va identificato il concetto che meglio rappresenta  una scatola nera: questo comporta astrazione

Scatole nere

Approccio alla programmazione orientato agli oggetti

Il software viene incapsulato in  scatole nere (oggetti)

Diversi livelli di astrazione

 Un utente di computer usa un programma costruito  tramite oggetti senza sapere nulla di programmazione 

 Un programmatore può usare un oggetto senza  conoscerne i dettagli di funzionamento

 Gli oggetti usati da un programmatore sono  programmati da... altri programmatori

 Un oggetto contiene... altri oggetti

(18)

35

Il progetto di una classe: 

BankAccount

Progettare la classe BankAccount

Vogliamo progettare la classe BankAccount, che  descriva il comportamento di un conto corrente  bancario

Quali caratteristiche sono essenziali al concetto di  conto corrente bancario?

 Possibilità di versare denaro

 Possibilità di prelevare denaro

 Possibilità di conoscere il saldo attuale

Queste caratteristiche definiscono l'interfaccia  pubblica della classe

(19)

37

Progettare la classe BankAccount

Le operazioni consentite dal comportamento di un  oggetto si effettuano mediante invocazione di metodi

Dobbiamo definire tre metodi

Tali metodi consentono di

 depositare denaro nel conto

 prelevare denaro dal conto

 conoscere il saldo

account.deposit(1000);

account.withdraw(500);

double balance = account.getBalance();

public void deposit(double amount);

public void withdraw(double amount);

public double getBalance();

Definizioni di metodi

La definizione di un metodo inizia sempre con la sua  intestazione (o firma, o signature), composta da

 uno specificatore di accesso

In questo caso public, altre volte vedremo private

 il tipo di dati restituito dal metodo (double, void...)

 il nome del metodo (deposit, withdraw, getBalance)

 un elenco di parametri, eventualmente vuoto,  racchiuso tra parentesi tonde

di ogni parametro si indica il tipo ed il nome

più parametri sono separati da una virgola public void deposit(double amount)

public double getBalance()

(20)

39

Definizioni di metodi

L'intestazione di un metodo è seguita dal corpo del  metodo stesso, composto da

 un insieme di enunciati che specificano le azioni svolte  dal metodo stesso

 racchiusi tra parentesi graffe

public void deposit(double amount) {

//corpo del metodo }

public double getBalance() {

//corpo del metodo }

Metodi di accesso e modificatori

 Metodo d'accesso: accede ad un oggetto e  restituisce informazioni senza modificarlo

getBalance è metodo di accesso

length della classe String è metodo di accesso

getX, getY, getWidth, getHeight della classe  Rectangle sono metodi di accesso

Metodo modificatore: altera lo stato di un oggetto

deposit e withdraw sono metodi modificatori

translate della classe Rectangle è un metodo  modificatore

(21)

41

Costruttori

Ripasso: costruire oggetti 

Abbiamo detto che per creare un nuovo oggetto di  una classe si usa l’operatore new seguito dal nome  della classe e da una coppia di parentesi tonde

L’operatore new crea un nuovo oggetto e ne  restituisce un riferimento, assegnabile ad una  variabile oggetto del tipo appropriato

new BankAccount();

BankAccount account = new BankAccount();

account BankAccount

(22)

43

I costruttori

Nella realizzazione della classe BankAccount  bisogna includere il codice per creare un nuovo 

conto bancario, ad esempio con saldo iniziale a zero.

Per consentire la creazione di un nuovo oggetto di  una classe, inizializzandone lo stato, dobbiamo  scrivere un nuovo metodo, il costruttore della  classe

public BankAccount() {

//corpo del costruttore }

I costruttori hanno  sempre lo stesso  nome della classe

I costruttori

Sintassi:

Lo scopo principale di un costruttore è quello di  inizializzare un oggetto della classe 

I costruttori, come i metodi, sono solitamente 

pubblici, per consentire a chiunque di creare oggetti  della classe

La sintassi utilizzata per definire i costruttori è molto  simile a quella dei metodi, ma

 il nome dei costruttori è sempre uguale a quello della  classe

 i costruttori non restituiscono alcun valore e non  bisogna neppure dichiarare che restituiscono void

tipoAccesso NomeClasse(TipoParametro nomeParametro,...) { //realizzazione del costruttore

}

(23)

45

Invocazione di costruttori

I costruttori si invocano soltanto con l’operatore new

L’operatore new riserva la memoria per l’oggetto,  mentre il costruttore definisce il suo stato iniziale 

Il valore restituito dall’operatore new è il riferimento  all’oggetto appena creato e inizializzato

quasi sempre il valore dell’operatore new viene  memorizzato in una variabile oggetto

BankAccount account = new BankAccount();

// ora account ha saldo zero

new BankAccount();

Una classe con più costruttori

Una classe può avere più di un costruttore

Ad esempio, definiamo un costruttore per creare un  nuovo conto bancario con un saldo iniziale diverso  da zero

public BankAccount()

{ // corpo del costruttore // inizializza il saldo a 0 }

public BankAccount(double initialBalance) { // corpo del costruttore

// inizializza il saldo a initialBalance }

(24)

47

Una classe con più costruttori

Per usare il nuovo costruttore di BankAccount,  bisogna fornire il parametro initialBalance

Notiamo che, se esistono più costruttori in una 

classe, hanno tutti lo stesso nome, perché devono  comunque avere lo stesso nome della classe

 questo fenomeno (più metodi o costruttori con lo  stesso nome) è detto sovraccarico del nome  (overloading)

 il compilatore decide quale costruttore invocare 

basandosi sul numero e sul tipo dei parametri forniti  nell’invocazione

BankAccount account = new BankAccount(500);

Una classe con più costruttori

Il compilatore effettua la risoluzione dell’ambiguità  nell’invocazione di costruttori o metodi sovraccarichi

Se non trova un costruttore che corrisponda ai 

parametri forniti nell’invocazione, segnala un errore  semantico

// NON FUNZIONA!

BankAccount a = new BankAccount("tanti soldi");

cannot resolve symbol

symbol     : constructor BankAccount (java.lang.String) location    : class BankAccount

(25)

49

Sovraccarico del nome

Se si usa lo stesso nome per metodi diversi, il nome  diventa sovraccarico (nel senso di carico di 

significati diversi…)

 questo accade spesso con i costruttori, dato che se  una classe ha più di un costruttore, essi devono avere  lo stesso nome

 accade più di rado con i metodi, ma c’è un motivo ben  preciso per farlo (ed è bene farlo in questi casi)

usare lo stesso nome per metodi diversi (che richiedono  parametri di tipo diverso) sta ad indicare che viene 

compiuta la stessa elaborazione su tipi di dati diversi

Sovraccarico del nome

La libreria standard di Java contiene numerosi  esempi di metodi sovraccarichi

Quando si invoca un metodo sovraccarico, il 

compilatore risolve l’invocazione individuando quale  sia il metodo richiesto sulla base dei parametri  espliciti che vengono forniti

public class PrintStream { ...

public void println(int n) {...}

public void println(double d) {...}

...

}

(26)

51

Definire una classe

Definizione di classe

Sintassi:

Le variabili di esemplare memorizzano lo stato di un  oggetto

La classe BankAccount deve avere un campo di  esemplare che permetta di memorizzare il saldo di un  oggetto di tipo BankAccount

tipoAccesso class nomeClasse

{ costruttori (intestazione e corpo) metodi (intestazione e corpo)

variabili (campi) di esemplare }

(27)

53

Definire la classe BankAccount

public class BankAccount { //Costruttori

public BankAccount()

{ corpo del costruttore }

public BankAccount(double initialBalance) { corpo del costruttore }

//Metodi

public void deposit(double amount) { realizzazione del metodo }

public void withdraw(double amount) { realizzazione del metodo }

public double getBalance() { realizzazione del metodo }

//Campi di esemplare ...

}

È tutto chiaro? …

1. Come si può svuotare il conto bancario account  usando i metodi dell’interfaccia pubblica della  classe?

2. Supponete di voler realizzare una più potente  astrazione di conto bancario che tenga traccia  anche di un numero di conto. Come va 

modificata l’interfaccia pubblica?

(28)

55

Variabili di esemplare

Lo stato di un oggetto

Gli oggetti (quasi tutti…) hanno bisogno di 

memorizzare il proprio stato attuale, cioè l’insieme  dei valori che 

descrivono l’oggetto e 

influenzano (anche se non necessariamente) il  risultato dell’invocazione dei metodi dell’oggetto

Gli oggetti della classe BankAccount hanno bisogno  di memorizzare il valore del saldo del conto bancario  che rappresentano

Lo stato di un oggetto viene memorizzato mediante  variabili di esemplare (o “variabili di istanza”, 

instance variables)

(29)

57

Dichiarare variabili di esemplare

Sintassi:

Scopo: definire una variabile nomeVariabile di tipo  TipoVariabile, una cui copia sia presente in ogni  oggetto della classe NomeClasse

Esempio:

public class NomeClasse { ...

tipoDiAccesso TipoVariabile nomeVariabile;

...

}

public class BankAccount { ...

private double balance;

...

}

Variabili di esemplare

Ciascun oggetto (“esemplare”) della classe ha una  propria copia delle variabili di esemplare

tra le quali non esiste nessuna relazione: possono  essere modificate indipendentemente l’una dall’altra

account1

balance 1000

BankAccount

account2

balance 2000

BankAccount

(30)

59

Variabili di esemplare

Così come i metodi sono di solito “pubblici” (public),  le variabili di esemplare sono di solito “private” 

(private)

Le variabili di esemplare private possono essere lette  o modificate soltanto da metodi della classe a cui  appartengono

 le variabili di esemplare private sono nascoste (hidden)  al programmatore che utilizza la classe, e possono 

essere lette o modificate soltanto mediante  l’invocazione di metodi pubblici della classe

 questa caratteristica dei linguaggi di programmazione  orientati agli oggetti si chiama incapsulamento o  information hiding

Incapsulamento

Poiché la variabile balance di BankAccount è  private, non vi si può accedere da metodi che non  siano della classe (errore semantico segnalato dal  compilatore)

Si possono usare solo i metodi pubblici!

/* codice interno ad un metodo che non appartiene a BankAccount */

double b = account.balance; // ERRORE

balance has private access in BankAccount

double b = account.getBalance(); // OK

(31)

61

Incapsulamento

L’incapsulamento ha molti vantaggi, soltanto pochi  dei quali potranno essere evidenziati in questo corso  di base

Il vantaggio fondamentale è quello di impedire  l’accesso incontrollato allo stato di un oggetto,  impedendo così anche che l’oggetto venga 

(accidentalmente o deliberatamente) posto in uno  stato inconsistente

Il progettista della classe BankAccount potrebbe  definire (ragionevolmente) che soltanto un saldo non  negativo rappresenti uno stato consistente per un  conto bancario

Incapsulamento

Dato che il valore di balance può essere modificato  soltanto invocando i metodi deposit o withdraw, il  progettista può impedire che diventi negativo, magari  segnalando una condizione d’errore

Se invece fosse possibile assegnare direttamente un  valore a balance dall’esterno, ogni sforzo del 

progettista di BankAccount sarebbe vano

 Si noti che, per lo stesso motivo e anche per realismo,  non esiste un metodo setBalance, dato che il saldo di  un conto bancario non può essere impostato ad un  valore qualsiasi!

(32)

63

È tutto chiaro? …

1. Si supponga di modificare la classe 

BankAccount in modo che ogni conto bancario  abbia anche un numero di conto. Come si 

modificano i campi di esemplare?

2. Quali sono i campi di esemplare della classe  Rectangle?

Realizzare costruttori e 

metodi

(33)

65

I metodi di BankAccount

La realizzazione dei costruttori e dei metodi di  BankAccount è molto semplice

 lo stato dell’oggetto (il saldo del conto) è memorizzato  nella variabile di esemplare balance

 i costruttori devono inizializzare la variabile balance

 quando si deposita o si preleva una somma di denaro,  il saldo del conto si incrementa o si decrementa della  somma specificata

il metodo getBalance restituisce il valore del saldo  corrente memorizzato nella variabile balance

Per semplicità, questa realizzazione non impedisce  che un conto assuma saldo negativo

I costruttori di BankAccount

public class BankAccount {

public BankAccount() {

balance = 0;

}

public BankAccount(double initialBalance) {

balance = initialBalance;

} ...

}

(34)

67

Il costruttore predefinito

Cosa succede se non definiamo un costruttore per  una classe?

 il compilatore genera un costruttore predefinito

 (senza alcuna segnalazione d’errore)

Il costruttore predefinito di una classe

 è pubblico e non richiede parametri

 inizializza tutte le variabili di esemplare

a zero le variabili di tipo numerico

a false le variabili di tipo boolean

al valore speciale null le variabili oggetto, in modo che  tali variabili non si riferiscano ad alcun oggetto

I metodi di BankAccount

public class BankAccount { ...

public void deposit(double amount) { balance = balance + amount;

}

public void withdraw(double amount) { balance = balance - amount;

}

public double getBalance() { return balance;

}

private double balance;

}

(35)

69

L’enunciato return

Sintassi:

Scopo: terminare l’esecuzione di un metodo,  ritornando all’esecuzione sospesa del metodo  invocante

 se è presente una espressione, questa definisce il  valore restituito dal metodo e deve essere del tipo  dichiarato nella firma del metodo

Al termine di un metodo con valore restituito di tipo  void, viene eseguito un return implicito

 il compilatore segnala un errore se si termina senza  un enunciato return un metodo con un diverso tipo di  valore restituito

return espressione;

return;

La classe BankAccount completa

public class BankAccount { public BankAccount() { balance = 0;

} public BankAccount(double initialBalance) { balance = initialBalance;

} public void deposit(double amount) { balance = balance + amount;

} public void withdraw(double amount) { balance = balance - amount;

} public double getBalance() { return balance;

} private double balance;

}

(36)

71

È tutto chiaro? …

1. Come è stato realizzato il metodo getWidth()  della classe Rectangle?

2. Come è stato realizzato il metodo translate della  classe Rectangle?

Parametri espliciti/impliciti

(37)

73

I parametri dei metodi

Cosa succede quando invochiamo il metodo?

L’esecuzione del metodo dipende da due valori

 il riferimento all’oggetto account

 il valore 500

Quando viene eseguito il metodo, il suo parametro  esplicito amount assume il valore 500

 esplicito perché compare nella firma del metodo

A quale variabile balance si riferisce il metodo?

 si riferisce alla variabile che appartiene all’oggetto  account con cui viene invocato il metodo

account è il parametro implicito del metodo 

public void deposit(double amount) { balance = balance + amount;

}

account.deposit(500);

Il riferimento null

(38)

75

Il riferimento null

Una variabile di un tipo numerico fondamentale  contiene sempre un valore valido (eventualmente  casuale, se non è stata inizializzata in alcun modo)

Una variabile oggetto può invece contenere 

esplicitamente un riferimento a nessun oggetto  valido assegnando alla variabile il valore null, che è  una parola chiave del linguaggio

 vedremo in seguito applicazioni utili di questa proprietà

 in questo caso la variabile è comunque inizializzata BankAccount account = null;

Il riferimento null

Diversamente dai valori numerici, che in Java non  sono oggetti, le stringhe sono oggetti

una variabile oggetto di tipo String può, quindi,  contenere un riferimento null

String greeting = "Hello";

String emptyString = ""; // stringa vuota

String nullString = null; // riferimento null int x1 = greeting.length(); // vale 5

int x2 = emptyString.length(); // vale 0

// nel caso seguente l’esecuzione del programma // termina con un errore

int x3 = nullString.length(); // errore

(39)

77

Usare un riferimento null

Una variabile oggetto che contiene un riferimento null  non si riferisce ad alcun oggetto

 non può essere usata per invocare metodi

Se viene usata per invocare metodi, l’interprete 

termina l’esecuzione del programma, segnalando un  eccezione di tipo NullPointerException (pointer è un  sinonimo di reference, “riferimento”)

Collaudare una classe

(40)

79

Usare la classe BankAccount

Senza sapere come sia stata realizzata la classe  BankAccount, siamo in grado di utilizzarla in un  programma

 apriamo un nuovo conto bancario e depositiamo  un  po’ di denaro

double initialDeposit = 1000;

BankAccount account = new BankAccount();

System.out.println("Saldo: " + account.getBalance());

account.deposit(initialDeposit);

System.out.println("Saldo: " + account.getBalance());

Saldo: 0 Saldo: 1000

Usare la classe BankAccount

Trasferiamo denaro da un conto ad un altro

Calcoliamo e accreditiamo gli interessi di un conto

double amount = 500;

account1.withdraw(amount);

account2.deposit(amount);

double rate = 0.05; // interessi del 5%

double amount = account.getBalance() * rate;

account.deposit(amount);

(41)

81

Classi di collaudo

Usiamo la classe BankAccount per risolvere un  problema specifico

apriamo un conto bancario, saldo iniziale 10000 euro

sul conto viene accreditato un interesse annuo del 5% del  valore del saldo, senza fare prelievi né depositi

qual è il saldo del conto dopo due anni?

BankAccount non contiene un metodo main

Compilando BankAccount.java si ottiene BankAccount.class

Ma non possiamo eseguire BankAccount.class

Dobbiamo scrivere una classe di collaudo (o di test)  che contenga un metodo main nel quale

Costruiamo uno o più oggetti della classe da collaudare

Invochiamo i metodi della classe per questi oggetti

Visualizziamo i valori restituiti

Esempio: utilizzo di BankAccount

public class BankAccountTester

{ public static void main(String[] args)

{ BankAccount acct = new BankAccount(10000);

final double RATE = 5;

// calcola gli interessi dopo il primo anno

double interest = acct.getBalance() * RATE / 100;

// somma gli interessi dopo il primo anno acct.deposit(interest);

System.out.println("Saldo dopo un anno: "

+ acct.getBalance() + " euro");

// calcola gli interessi dopo il secondo anno interest = acct.getBalance() * RATE / 100;

// somma gli interessi dopo il secondo anno acct.deposit(interest);

System.out.println("Saldo dopo due anni: "

+ acct.getBalance() + " euro");

}}

(42)

83

È tutto chiaro? …

1. Quando eseguo BankAccountTester, quanti 

oggetti di tipo BankAccount vengono costruiti? E  quanti di tipo BankAccountTester?

Un programma con più classi

Per scrivere semplici programmi con più classi, si  possono usare due strategie (equivalenti)

 Scrivere ciascuna classe in un file diverso, ciascuno  avente il nome della classe con estensione .java

Tutti i file vanno tenuti nella stessa cartella

Tutti i file vanno compilati separatamente

Solo la classe di collaudo (contenente il metodo main) va  eseguita

 Scrivere tutte le classi in un unico file

un file .java può contenere una sola classe public

la classe contenente il metodo main deve essere public

le altre non devono essere public (non serve scrivere  private, semplicemente non si indica l’attributo public)

il file .java deve avere il nome della classe public

Nel compito faremo così!!

(43)

85

Riassunto: progettare una classe

1. Capire cosa deve fare un oggetto della classe

 Elenco in linguaggio naturale delle operazioni  possibili

2. Specificare l'interfaccia pubblica

 Ovvero, definire i metodi tramite le loro intestazioni 3. Documentare l'interfaccia pubblica

4. Identificare i campi di esemplare a partire dalle  intestazioni dei metodi

5. Realizzare costruttori e metodi

 Se avete problemi a realizzare un metodo forse  dovete riesaminare i passi precedenti

6. Collaudare la classe con un programma di collaudo

Materiale di complemento

(capitolo 3)

(44)

87

Categorie e cicli di vita delle  variabili

 Per ora saltiamo questa sezione (3.7)

• Ne parliamo più avanti (capitolo 9)

Parametri impliciti e il  riferimento this

 Per ora saltiamo questa sezione (3.8)

• Ne parliamo più avanti (capitolo 9)

(45)

89

Commenti di  documentazione

Commentare l'interfaccia pubblica

I commenti ai metodi sono importantissimi per rendere il  codice comprensibile a voi ed agli altri!

Java ha delimitatori speciali per commenti di  documentazione

@param nomeparametro per  descrivere un parametro esplicito

/**

Preleva denaro dal conto

@param amount importo da prelevare

*/

public void withdraw(double amount)

{

//corpo del metodo }

/**

Ispeziona saldo attuale @return saldo attuale

*/

public double getBalance() {

//corpo del metodo }

(46)

91

Commentare l'interfaccia pubblica

Inserire brevi commenti anche alla classe, per  illustrarne lo scopo

Usando commenti di documentazione in questo  formato si può generare in maniera automatica  documentazione in html

Genera un documento NomeClasse.html ben 

formattato e con collegamenti ipertestuali, contenente i  commenti a NomeClasse

/**

Un conto bancario ha un saldo

modificabile tramite depositi e prelievi

*/

public class BankAccount {

...

}

javadoc NomeClasse.java

(47)

93

Decisioni (capitolo 5)

L’enunciato if

Il programma precedente consente di prelevare tutto  il denaro che si vuole

 il saldo balance può diventare negativo

È una situazione assai poco realistica!

Il programma deve controllare il saldo ed agire di  conseguenza, consentendo il prelievo oppure no

balance = balance - amount;

(48)

95

L’enunciato if

L’enunciato if si usa per  realizzare una decisione ed  è diviso in due parti

 una verifica

 un corpo

Il corpo viene eseguito se e  solo se la verifica ha 

successo

if (amount <= balance)

balance = balance - amount;

Tipi di enunciato in Java

Enunciato semplice

Enunciato composto

Blocco di enunciati

balance = balance - amount;

if (x >= 0) x=0;

{ zero o più enunciati di qualsiasi tipo }

(49)

97

Un nuovo problema

Proviamo ora ad emettere un messaggio d’errore in  caso di prelievo non consentito

Problema: se si modifica la prima verifica, bisogna  ricordarsi di modificare anche la seconda (es. viene  concesso un fido sul conto, che può “andare in 

rosso”)

Problema: se il corpo del primo if viene eseguito, la  verifica del secondo if usa il nuovo valore di balance,  introducendo un errore logico 

 quando si preleva più della metà del saldo disponibile

if (amount <= balance)

balance = balance - amount;

if (amount > balance)

System.out.println("Conto scoperto");

La clausola else

Per realizzare un’alternativa, si utilizza la clausola  else dell’enunciato if

Vantaggio: ora c’è una sola verifica

 se la verifica ha successo, viene eseguito il primo  corpo dell’enunciato if/else

 altrimenti, viene eseguito il secondo corpo

if (amount <= balance)

balance = balance - amount;

else

System.out.println("Conto scoperto");

(50)

99

if (amount <= balance)

balance = balance - amount;

else

{ System.out.println("Conto scoperto");

balance = balance – OVERDRAFT_PENALTY;

}

La clausola else

L’enunciato if

Sintassi:

Scopo: eseguire enunciato1 se e solo se la 

condizione è vera; se è presente la clausola else,  eseguire enunciato2 se e solo se la condizione è  falsa

Spesso il corpo di un enunciato if è costituito da più  enunciati da eseguire in sequenza; racchiudendo tali  enunciati tra una coppia di parentesi graffe { } si crea  un blocco di enunciati, che può essere usato come  corpo

if (condizione) enunciato1

if (condizione) enunciato1 else enunciato2

if (amount <= balance)

{ balance = balance - amount;

System.out.println("Prelievo accordato");

}

(51)

101

È tutto chiaro? …

1. Perché nell’esempio precedente abbiamo usato  la condizione amount <= balance e non la 

condizione amount < balance?

2. Qual è l’errore logico nell’enunciato seguente, e  come lo si può correggere?

if (amount <= balance)

newBalance = balance – amount;

balance = newBalance;

Confrontare valori numerici

(52)

103

Confrontare valori

Le condizioni dell’enunciato if sono molto spesso dei  confronti tra due valori

Gli operatori di confronto si chiamano operatori  relazionali

> Maggiore

>= Maggiore o uguale

< Minore

<= Minore o uguale

== Uguale

!= Diverso

if (x >= 0)

Attenzione: 

negli operatori costituiti da due caratteri non vanno inseriti spazi intermedi

Operatori relazionali

Fare molta attenzione alla differenza tra l’operatore  relazionale == e l’operatore di assegnazione =

a = 5; // assegna 5 ad a if (a == 5) // esegue enunciato enunciato // se a è uguale a 5

(53)

105

Confronto di numeri in  virgola mobile

Confrontare numeri in virgola mobile

I numeri in virgola mobile hanno una precisione  limitata ed i calcoli possono introdurre errori di  arrotondamento e troncamento

Tali errori sono inevitabili e bisogna fare molta  attenzione nella formulazione di verifiche che  coinvolgono numeri in virgola mobile

double r = Math.sqrt(2);

double x = r * r;

if (x == 2)

System.out.println("OK");

else

System.out.println("Non ci credevi?");

(54)

107

Confrontare numeri in virgola mobile

Affinché gli errori di arrotondamento non influenzino  la logica del programma, i confronti tra numeri in  virgola mobile devono prevedere una tolleranza

 Verifica di uguaglianza tra x ed y (di tipo double):

| x ­ y | < 

ε

         con 

ε

 = 1E­14

 Scelta migliore se x,y sono molto grandi o molto piccoli

| x ­ y | < 

ε  

max(|x|,|y|)

 

   con 

ε

 = 1E­14

(questo valore di ε è ragionevole per numeri double) 

Il codice per questa verifica è

final double EPSILON = 1E-14;

if ( Math.abs(x - y) <=

EPSILON*Math.max(Math.abs(x),Math.abs(y)) ) ...

Confrontare numeri in virgola mobile

Possiamo definire un metodo statico che verifichi  l’uguaglianza con tolleranza

public class Numeric

{ public static boolean approxEqual(double x, double y) { final double EPSILON = 1E-14;

double xyMax = Math.max(Math.abs(x),Math.abs(y));

return Math.abs(x - y) <= EPSILON * xyMax;

}} double r = Math.sqrt(2);

if (Numeric.approxEqual(r * r, 2))

System.out.println("Tutto bene...");

else System.out.println("Questo non succede...");

(55)

109

Confronto di stringhe

Confronto di stringhe

Per confrontare stringhe si usa il metodo equals

Per confrontare stringhe ignorando la differenza tra  maiuscole e minuscole si usa

Non usare mai l’operatore di uguaglianza per  confrontare stringhe! Usare sempre equals

 Se si usa l’operatore uguaglianza, il successo del  confronto sembra essere deciso in maniera “casuale”

 In realtà dipende da come è stata progettata la Java  Virtual Machine e da come sono state costruite le due  stringhe

if (s1.equals(s2))

if (s1.equalsIgnoreCase(s2))

(56)

111

Confronto di stringhe

Confrontando con l’operatore di uguaglianza due  riferimenti a stringhe si verifica se i riferimenti  puntano allo stesso oggetto stringa

Il confronto s1 == s2 è vero, perché puntano allo  stesso oggetto stringa

Il confronto s1 == s3 è falso, perché puntano ad  oggetti diversi, anche se tali oggetti hanno lo stesso  contenuto (sono “identici”)

String s1 = "Stringa";

String s2 = s1;

String s3 = "String";

s3 = s3 + "a"; // s3 contiene "Stringa"

Confronto di stringhe

Stringa

s1 s2

s3

String s1 = "Stringa";

String s2 = s1;

String s3 = "String";

s3 = s3 + "a";

String

Stringa

String

(57)

113

Confronto di stringhe

Confrontando invece con il metodo equals due  riferimenti, si verifica se i riferimenti puntano ad  stringhe con lo stesso contenuto

Il confronto s1.equals(s3) è vero, perché puntano a  due oggetti String identici

Nota: per verificare se un riferimento si riferisce a  null, bisogna usare invece l’operatore di uguaglianza  e non il metodo equals

String s1 = "Stringa";

String s2 = s1;

String s3 = "String";

s3 = s3 + "a"; // s3 contiene "Stringa"

if (s == null)

Ordinamento lessicografico

Se due stringhe sono diverse, è possibile conoscere  la relazione che intercorre tra loro secondo 

l’ordinamento lessicografico, simile al comune  ordinamento alfabetico

Il confronto lessicografico tra stringhe si esegue con il  metodo compareTo

Il metodo compareTo restituisce un valore int 

 negativo se s1 precede s2 nell’ordinamento

 positivo se s1 segue s2 nell’ordinamento

 zero se s1 e s2 sono identiche 

if (s1.compareTo(s2) < 0)

(58)

115

Confronto lessicografico

Partendo dall’inizio delle stringhe, si confrontano i  caratteri in posizioni corrispondenti, finché una delle  stringhe termina oppure due caratteri sono diversi

 se una stringa termina, essa precede l’altra 

se terminano entrambe, sono uguali

 altrimenti, l’ordinamento tra le due stringhe è uguale  all’ordinamento alfabetico tra i due caratteri diversi

carta  precede  castano

c a r t a

c a s t a n o

lettere

uguali r precede s

Confronto lessicografico

Il confronto lessicografico genera un ordinamento  simile a quello di un comune dizionario

…con qualche differenza… 

 Tra i caratteri non ci sono solo le lettere

i numeri precedono le lettere

tutte le lettere maiuscole precedono tutte le lettere  minuscole

il carattere di “spazio bianco” precede tutti gli altri  caratteri

L’ordinamento lessicografico è definito dallo standard  Unicode, http://www.unicode.org

(59)

117

Confrontare oggetti

Confronto di oggetti

Come per le stringhe, l’operatore == tra due variabili  oggetto verifica se i due riferimenti puntano allo stesso  oggetto, e non verifica l'uguaglianza tra oggetti

Il metodo equals può essere applicato a qualsiasi  oggetto, perché è definito nella classe Object, da cui  derivano tutte le classi

È compito di ciascuna classe ridefinire il metodo equals,  come fa la classe String

altrimenti il metodo equals di Object usa semplicemente  l’operatore di uguaglianza

Il metodo equals di ciascuna classe deve effettuare il  confronto delle caratteristiche (variabili di esemplare)  degli oggetti di tale classe

Per ora usiamo equals solo per classi della libreria standard

(60)

119

Ordinamento di oggetti

Il metodo compareTo visto per le stringhe può 

essere applicato a molti altri oggetti, (ma non tutti  perché non è definito nella classe Object)

È compito di ciascuna classe definire in maniera  opportuna il metodo compareTo, come fa la classe  String, secondo una opportuna nozione di 

ordinamento

Il metodo compareTo di una classe restituirà sempre  un valore int 

 negativo se obj1 precede obj2 nell’ordinamento

 positivo se obj1 segue obj2 nell’ordinamento

 zero se obj1 e obj2 sono identici 

if (obj1.compareTo(obj2) < 0)

È tutto chiaro? …

1.

Qual è il valore di s.length() se s contiene (a) un  riferimento alla stringa vuota “”   (b) un riferimento alla  stringa “ “ contenente solo uno spazio (c) il valore null ?

2.

Quali di questi confronti hanno errori di sintassi? Quali  hanno poca utilità dal punto di vista logico?

String a = “1”;

String b = “one”;

double x = 1;

double y = 3 * (1.0 / 3);

(a)

a == “1”;

(b)

a == null;

(c)

a.equals(“”);

(d)

a == b;

(e)

a == x;

(f)

x == y;

(g)

x – y == null;

(h)

x.equals(y);

Riferimenti

Documenti correlati

¨  Nell’input di stringhe, la scanf scarta automaticamente i white space iniziali e continua a leggere fino a quando incontra un white space (quindi non si può usare la scanf

cost = 10; // Hawaii più costoso else // NON FUNZIONA. cost = 20; // estero ancora

cost = 20; // estero ancora più

•  Accoda il contenuto della stringa passata come secondo parametro nella stringa passata come primo parametro int main () {.

È proprio a questo livello che si inserisce ed acquista interesse l’elaborato di tesi: si studierà la dinamica di una stringa elementare in maniera consistente con la

Gli studi condotti al Meyer hanno potuto dimostrare che con il nuovo test non si individuano solo i bambini con la forma più grave di difetto di ADA, ma anche quelli con la forma

[r]

aS aaS aaaS aaaCbC aaacCbC aaaccbC aaaccbS aaaccbaS aaaccbaaS aaaccbaa.