file Counter.java
public class Counter { int value = 0; public int increment() { value ++; return value; } public int getValue() { return value; } }
public
altrimenti sarebbe inaccessibile dall'esterno del file.
value
.Questa variabile e' inaccessibile dall'esterno realizzando l'incapsulazione.
increment
e getValue
che definiscono il suo comportamento.
Notate come il secondo metodo e' un metodo getter introdotto solo
per realizzare l'incapsulazione.
value++
indica la stessa cosa di value=value+1
file MyApplication.java
public class MyApplication { public static void main (String args[]) { Counter c1 = new Counter(); Counter c2 = new Counter(); System.out.println("Counter 1 has value "+c1.getValue()); System.out.println("Counter 2 has value "+c2.getValue()); c1.increment(); c1.increment(); c2.increment(); System.out.println("Counter 1 now has value "+c1.getValue()); System.out.println("Counter 2 now has value "+c2.getValue()); } }
Counter
.
main
con l'istruzione:
public static void main (String args[]) { }per indicare dove deve cominciare l'esecuzione del programma Java. In gergo Java un programma col metodo
main
e' un'applicazione per distinguerlo dai programmi applet (applicazioncine) che girano nel browser.Un'applicazione
si fa partire con l'istruzione java nome_della_classe_contenente_il_metodo_mainE' possibile inserire anche una lista di stringhe di caratteri che vengono assegnati agli elementi del vettore
args
Object
.
System.out.println()
richiama il metodo println della classe out contenuta a sua volta nella classe System. Notate che essendo il metodo statico puo' essere richiamato usando
il nome della classe senza dover instanziare nessun oggetto.
new
e'
di far allocare lo spazio necessario per contenere l'oggetto dalla zona di memoria chiamata heap facendo puntare la variabile (che prima era uguale a
null
) a questa zona. In Java le variabili che descrivono
oggetti si comportano in maniera molto differente
di quelle che si riferiscono a dati primitivi.
BigCounter
estendendo la classe Counter
dell'applicazione 1 modificando il metodo increment
.Usare la classe originale insieme alla classe ridefinita.Mostrare
l'uso di super() per estendere un metodo preesistente.S
file BigCounter.java
public class BigCounter extends Counter { public int increment() { value = value + 2; return value; } }
extends
per indicare che vogliamo estendere un'altra classe, realizzando l'ereditarieta'.
value = value+2; return value;possiamo scrivere
super.increment();return super.increment();richiamando il metodo della classe madre.
file MyApplication.java
public class MyApplication { public static void main (String args[]) { Counter c1 = new Counter(); Counter c2 = new BigCounter(); System.out.println("Counter 1 has value "+c1.getValue()); System.out.println("Counter 2 has value "+c2.getValue()); c1.increment(); c1.increment(); c2.increment(); System.out.println("Counter 1 now has value "+c1.getValue()); System.out.println("Counter 2 now has value "+c2.getValue()); } }
Counter
e un oggetto BigCounter
(che e' anche Counter
) ma il codice del programma e' rimasto lo stesso:questo e' il polimorfismo in azione. All'atto dell'esecuzione il programma si preoccupa di richiamare il metodo corretto.
Counter
in modo da poter dare un valore iniziale al contatore.
S
file Counter.java
public class Counter { int value; public Counter() { this(0); } public Counter (int startingValue) { value = startingValue; } public int increment() { value ++; return value; } public int getValue() { return value; } }
this()
si riferisce al
costruttore della classe nel quale ci troviamo. super()
si riferisce invece al costruttore della classe madre.
file MyApplication.java
public class MyApplication { public static void main (String args[]) { Counter c1 = new Counter(3); BigCounter c2 = new BigCounter(5); System.out.println("Counter 1 has value "+c1.getValue()); System.out.println("Counter 2 has value "+c2.getValue()); c1.increment(); c1.increment(); c2.increment(); System.out.println("Counter 1 now has value "+c1.getValue()); System.out.println("Counter 2 now has value "+c2.getValue()); } }
BigCounter
; questo e' possibile
perche' un BigCounter e' anche un Counter
.
super()
permette di definire il costruttore di una sottoclasse richiamando il costruttore
della superclasse.
file Sample.java
public class Sample { static int classValue = 0; int objectValue = 10; public static void printClassValue() { System.out.println("The class value "+classValue); } public static void setClassValue (int v) { classValue = v; } public void printObjectValue() { System.out.println("This object's value is "+objectValue); } public void setObjectValue(int v) { objectValue = v; } };
file MyApplication.java
public class MyApplication { public static void main (String args[]) { Sample.printClassValue(); // prints 0; Sample s1 = new Sample(); Sample s2 = new Sample(); s1.setClassValue(20); s1.setObjectValue(25); s1.printClassValue(); // prints 20 s2.printClassValue(); // prints also 20 s1.printObjectValue(); // prints 25 s2.printObjectValue(); // prints 10 Sample.setClassValue(15); s2.printClassValue(); // prints 15 s1.printClassValue(); // prints also 15 } }
Sample.setClassValue
e s1.setClassValue
fanno la stessa cosa.
printClassValue
e setClassValue
sono static
.
s1.printClassValue
e S2.printClassValue
daranno
sempre lo stesso risultato.
this
. Se volete riferirvi a variabili e metodi di oggetto, allora dovete
istanziare esplicitamente un oggetto della classe nella quale ci troviamo
ed usare il nome di quest'oggetto.Questo di solito crea confusione nei principianti.
Accumulator
simile alla classe Counter
.Definite
un'interfaccia comune alle due classi consistente in un metodo che stampa i valori dei contatori ed implementatela in ambedue le classi.
S
file StatusPrinter.java
public interface StatusPrinter { public void printStatus(); }
printStatus
file Accumulator.java
public class Accumulator implements StatusPrinter{ int sum = 0; public void add (int quantity) { sum = sum + quantity; } public int getSum () { return sum; } public void printStatus () { System.out.println ("Hi I'm an accumulator. My sum is "+sum); } }
Accumulator
ha due metodi propri e inoltre un
metodo ereditato dall'interfaccia StatusPrinter
e implementato (cioe' col codice definito) in questa classe.
file Counter.java
public class Counter implements StatusPrinter { int value = 0; public int increment() { value ++; return value; } public void printStatus() { System.out.println ("I'm a Counter. My value is " + value ); } public int getValue() { return value; } }
Counter
implementando la stessa interfaccia ridefinisce
anch'essa il metodo printStatus
.
file MyApplication.java
public class MyApplication { static void displayStuff (StatusPrinter s) { s.printStatus(); } public static void main (String args[]) { Accumulator a1 = new Accumulator(); Counter c1 = new Counter(); MyApplication.displayStuff (a1); MyApplication.displayStuff (c1); } }
displayStuff
che lavora
su dati di tipo StatusPrinter
e quindi con tutti gli oggetti
delle classi che implementano questa interfaccia.
displayStuff
non fa altro che richiamare il
metodo printStatus
sull'oggetto passato.
displayStuff
con oggetti di tipo diverso:un'esempio di messaggio generico a cui ogni oggetto
risponde a suo modo. Questo e' il polimorfismo in azione!
static
?Come
andrebbe riscritta la classe MyApplication
in modo da funzionare
con un metodo displayStuff
non statico?
SingleCounter
che puo' essere instanziata una sola volta realizzando un Singleton.
S
file SingleCounter.java
final class SingleCounter { private static SingleCounter s = new SingleCounter(0); private int value; private SingleCounter(int v){value=v;} public static SingleCounter instance(){return s;} public int increment() { value ++; return value; } public int getValue() { return value; } }
file MyApplication.java
public class MyApplication { public static void main (String args[]) { SingleCounter c1 = SingleCounter.instance(); c1.increment(); SingleCounter c2 = SingleCounter.instance(); c2.increment(); System.out.println("Counter 1 has value "+c1.getValue()); System.out.println("Counter 2 has value "+c2.getValue()); } }
import java.applet.Applet; import java.awt.*; public class Lifecycle extends Applet { int initCount=0; int startCount=0; int stopCount=0; int destroyCount=0; int paintCount=0; public void init() { ++initCount; System.out.println("init(): " + initCount); } public void start() { ++startCount; System.out.println("start() " + startCount); } public void stop() { ++stopCount; System.out.println("stop() " + stopCount); } public void destroy() { ++destroyCount; System.out.println("destroy() " + destroyCount); } public void paint(Graphics g) { ++paintCount; g.drawString("Ciao a tutti",20,20); System.out.println("paint(): " + paintCount); } }Guardate l'applet in funzione.
init
e' richiamato all'inizio, una volta per tutte.Viene richiamato anche se usiamo la finestra Location per riattivare l'applet.
start
a ogni reload dell'applet subito dopo stop
.paint
ogni volta che la finestra ha bisogno di essere ridipinta .destroy
viene richiamato solo se si torna indietro cliccando daccapo sul link all'applet.
i++
e ++i
hanno ambedue lo stesso risultato: i = i +1
. Quindi negli esempi visti finora i due usi sono equivalenti. La differenza si ha se voi fate un controllo
del valore di i nella maniera seguente:
i=5; if (++i == 6) //vero perche' il valore confrontato e' quello incrementato if (i++ == 6) //falso perche' il valore confrontato e' quello prima dell'incremento
import java.awt.*; import javax.swing.*; public class Lifecycle1 extends JApplet { Display disegno; int initCount=0; int startCount=0; int stopCount=0; int destroyCount=0; int paintCount=0; public void init() { disegno = new Display(); setContentPane(disegno); ++initCount; System.out.println("init(): " + initCount); } public void start() { ++startCount; System.out.println("start() " + startCount); } public void stop() { ++stopCount; System.out.println("stop() " + stopCount); } public void destroy() { ++destroyCount; System.out.println("destroy() " + destroyCount); } class Display extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); ++paintCount; g.drawString("Ciao a tutti",20,20); System.out.println("paint(): " + paintCount); } } }Guardate l'applet in funzione.
javax.swing
che contiene le classi JApplet e JPanel
.
JPanel
che ha tutti i metodi di
Applet
JPanel
setContentPane
definisce questo JPanel come Panel di sfondo dell'applet.
paintComponent
del JPanel
di sfondo.
Display
interna
alla classe che definisce l'applet.
super.paintComponent(g)
cancella il contenuto della finestra
prima di fare daccapo il disegno.
import javax.swing.*; public class nomeclasse extends JApplet { Display disegno; public void init() { disegno = new Display(); setContentPane(disegno); } class Display extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); } } }e' possibile modificare un qualsiasi applet 1.1 nella versione 2 di Java.
import java.awt.*; import javax.swing.*; public class Cerchio1 extends JApplet { int r, x, y; Display disegno; public void init() { disegno = new Display(); setContentPane(disegno); r = 50; x = 100; y=100; } class Display extends JPanel { public void paintComponent(Graphics g){ super.paintComponent(g); g.drawOval(x,y,2*r,2*r); System.out.println("x,y,r= "+x+" "+y+" "+r); } } }Guardate l'applet in funzione.
init
per dare un valore iniziale alle variabili x,y,r
paintComponent
disegna il cerchio usando questi valori,ogni volta che il browser lo richiede.
/* Questo applet disegna dei cerchi */ import java.awt.*; import javax.swing.*; public class Cerchio1 extends JApplet { Display disegno; int n,width,height; public void init() { disegno = new Display(); setContentPane(disegno); n = (int)(Math.random()*100); disegno.repaint(); } class Display extends JPanel { public void paintComponent(Graphics g){ super.paintComponent(g); width = getSize().width; height = getSize().height; System.out.println(n+" "+width+" "+height); for(int i=0;i < n;i++){ int r = (int)(Math.random()*width/2); int x = (int)(Math.random()*width); int y = (int)(Math.random()*height); g.setColor(new Color((float)Math.random(),(float)Math.random(),(float)Math.random())); g.fillOval(x,y,2*r,2*r); // System.out.println(x+" "+y+" "+r); } } } }Guardate l'applet in funzione.
getSize()
ritorna le dimensioni dell'applet sotto forma
di oggetto Rectangle
le cui proprieta' width e height
danno larghezza e altezza in pixel.
int r = (int)(Math.random()*width/2);La conversione e' obbligatoria solo se si fanno operazioni tra dati "incompatibili" :ad esempio un int in generale puo' non essere in grado di contenere il valore double tornato da Math.random()*width/2 , ma un double puo' contenere senza problemi un int e percio' l'operazione width/2 non richiede conversione.
init
. Invece paintComponent
viene richiamato ogni volta che l'applet deve essere ridisegnato. Da notare che non possiamo chiamare direttamente paintComponent
ma possiamo ,chiamando repaint()
,
suggerire al browser di farlo appena possibile.
Color
assieme al metodo setColor
(di Graphics
) ci permettono di definire i colori con triple di percentuali di
rosso,verde e blu'.
import java.awt.*; import javax.swing.*; public class Julia extends JApplet { Color col[]=new Color[221]; Display disegno; public void init() { disegno = new Display(); setContentPane(disegno); col[0] = new Color(255,0,0); col[1] = new Color(0,255,0); col[2] = new Color(0,0,255); col[3] = new Color(255,255,0); col[4] = new Color(0,255,255); col[5] = new Color(255,0,255); for(int i=6;i< 221;i++){ col[i]=new Color(i,0,0); } } class Display extends JPanel { public void paintComponent(Graphics g){ super.paintComponent(g); int width = getSize().width; int height = getSize().height; double c1,c2; double x,y; double incrementox=4./width; double incrementoy=3./height; int k; int maxit =220; double x1,y1,r; int i,j; double x0,y0; c1 = Math.random()*4.-2.; c2 = Math.random()*3.-1.5; for(x=-2.;x<2.;x=x+incrementox){ for(y=-1.5;y<1.5;y=y+incrementoy){ x0 =x; y0=y; for(k=1;k<maxit;k=k+1){ x1 = x0*x0 - y0*y0 + c1; y1 = 2.*x0*y0 + c2; r = x1*x1 + y1*y1; if(r > 4.)break; x0 = x1; y0 = y1; } if(k<220) { i = (int)(((x+2)/4)*width); j = (int)(((y+1.5)/3.)*height); g.setColor(col[k]); g.fillRect(i,j,1,1); } } } } } }Guardate l'applet in funzione.
Nomeclasse pippo[] = new Nomeclasse[n];crea un oggetto array
pippo
formato a sua volta da n
puntatori a terra (null) a oggetti Nomeclasse
.
init
questi puntatori vengono fatti
puntare ad altrettanti oggetti Color
creando una semplicissima tavolozza da usare per colorare il disegno.
Graphics
fillRect(x,y,1,1)
con gli argomenti che indicano un rettangolo al punto di coordinate x,y di dimensioni 1.
import java.awt.*; import javax.swing.*; public class Julia1 extends JApplet { int maxcol = 158; Color col[]=new Color[maxcol]; Display disegno; public void init() { disegno = new Display(); setContentPane(disegno); setcol(col); } class Display extends JPanel { public void paintComponent(Graphics g){ super.paintComponent(g); int width = getSize().width; int height = getSize().height; double c1,c2; double x,y; double incrementox=4./width; double incrementoy=3./height; int k; double x1,y1,r; int i,j; double x0,y0; c1 = Math.random()*4.-2.; c2 = Math.random()*3.-1.5; for(x=-2.;x<2.;x=x+incrementox){ for(y=-1.5;y<1.5;y=y+incrementoy){ x0 =x; y0=y; for(k=1;k<maxcol;k=k+1){ x1 = x0*x0 - y0*y0 + c1; y1 = 2.*x0*y0 + c2; r = x1*x1 + y1*y1; if(r > 4.)break; x0 = x1; y0 = y1; } if(k<maxcol) { i = (int)(((x+2)/4)*width); j = (int)(((y+1.5)/3.)*height); g.setColor(col[k]); g.fillRect(i,j,1,1); } } } } } public static void setcol(Color col[]){ int ncolr = 30; int i; col[0] = new Color(0,0,0); col[1] = new Color(0,0,0); col[2] = new Color(255,0,0); col[3] = new Color(0,255,0); col[4] = new Color(0,0,255); col[5] = new Color(255,255,0); col[6] = new Color(255,0,255); col[7] = new Color(0,255,255); for (i=0;i<ncolr;i++) { col[i+8] = new Color(interp(255,255,i/(double)(ncolr-1.)), interp(0,255,i/(double)(ncolr-1.)), interp(0,0,i/(double)(ncolr-1.))); } for (i=0;i<ncolr;i++) { col[i+ncolr+8] = new Color(interp(255,0,i/(double)(ncolr-1.)), interp(255,255,i/(double)(ncolr-1.)), interp(0,0,i/(double)(ncolr-1.))); } for (i=0;i<ncolr;i++) { col[i+2*ncolr+8] = new Color(interp(0,0,i/(double)(ncolr-1.)), interp(255,255,i/(double)(ncolr-1.)), interp(0,255,i/(double)(ncolr-1.))); } for (i=0;i<ncolr;i++) { col[i+3*ncolr+8] = new Color(interp(0,0,i/(double)(ncolr-1.)), interp(255,0,i/(double)(ncolr-1.)), interp(255,255,i/(double)(ncolr-1.))); } for (i=0;i<ncolr;i++) { col[i+4*ncolr+8] = new Color(interp(0,255,i/(double)(ncolr-1.)), interp(0,0,i/(double)(ncolr-1.)), interp(255,255,i/(double)(ncolr-1.))); } } static int interp(int a,int b,double f) { return (int)(a*(1-f)+b*f); } }Guardate l'applet in funzione.
import java.awt.*; import javax.swing.*; public class Pick extends JApplet { int maxcol = 158; Color col[]=new Color[maxcol]; Display disegno; public void init() { disegno = new Display(); setContentPane(disegno); Julia1.setcol(col); } class Display extends JPanel { public void paintComponent(Graphics g){ super.paintComponent(g); int width = getSize().width; int height = getSize().height; double c1,c2; int i,j,ncol; c1 = Math.random()-5.; c2 = Math.random()-5.; for(i=0;i<width;i++){ for(j=0;j<height;j++){ ncol = (int)(c1*(Math.sin(-11.+c2*i)+Math.sin(-12.+c2*j))); ncol = Math.abs(ncol)%maxcol+1; g.setColor(col[ncol]); g.fillRect(i,j,1,1); } } } } }Guardate l'applet in funzione.
setcol
dell'applet precedente essendo stato dichiarato:
public static void setcol(Color col[]){puo' essere richiamato come metodo di classe, senza dover instanziare nessun oggetto.
livello di accesso | public|(package) |
abstract | se presente,la classe non puo' essere istanziata.Usato in classi come Applet per definire un modello da implementare in sottoclassi. |
final | se presente,la classe non puo' essere ridefinita.Usato per proteggere classi di uso generale come String da possibili usi nocivi da parte di hacker. |
class NomeClasse | per convenzione il nome comincia con la maiuscola |
extends NomeSuperclasse | presente se la classe ne ridefinisce un'altra |
implements Interface1,Interface2,... | presente se la classe implementa una o piu' interfacce |
{ | alt+123 oppure SHIFT+[ |
variabili | |
costruttore | |
metodi | |
} | alt+125 oppure SHIFT+] |
livello di accesso | public|protected|(package o file)|private |
static | se presente,la variabile viene allocata indipendentemente dagli oggetti istanziati, in un'unica copia. |
final | se presente,la variabile non puo' essere ridefinita.Usato per costanti. |
transient | |
volatile | se presente, indica che la variabile e' condivisa tra piu' Thread e quindi ogni suo cambio di valore deve essere immediatamente accessibile. |
tipo | Uno degli 8 tipi primitivi oppure il nome di una classe |
nomevariabile | |
= espressione; | se presente,richiama il costruttore o indica il valore iniziale di un tipo primitivo. |
livello di accesso | public|protected|(package o file)|private |
static | se presente, indica metodi che possono essere richiamati senza instanziare oggetti,usando il nome della classe. |
abstract | se presente,il metodo non e' implementato. |
final | se presente,il metodo non puo' essere ridefinito. |
native | |
synchronized | se presente indica che il metodo deve eseguire solo se altri metodi sincronizzati in altri Thread non stanno eseguendo. Permette l'accesso esclusivo a risorse condivise. |
tipodivaloreritornato nomeMetodo | usare void se il metodo non ritorna nessun valore.Il nome del metodo comincia per convenzione con una lettera minuscola. |
(tipoarg1 nomearg1,tipoarg2 nomearg2,...) | lista di argomenti |
throws Eccezione1,Eccezione2,... | lista delle eccezioni lanciate da questo metodo |
{ | |
variabili locali | |
istruzioni del metodo | |
if(condizione)throw Eccezione; | lancio di eccezione |
return espressione; | normale ritorno con un valore |
} |
public static void main(String args[]){}indica un metodo molto particolare in quanto rende la classe che lo implementa un'applicazione e il metodo viene richiamato dal sistema operativo per primo all'atto dell'attivazione della stessa. args e' un vettore di stringhe che contiene le parole scritte dopo il comando java NomeClasse.
g.fillOval(x,y,2*r,2*r);
if (n > 0) { istruzioni... }else{ istruzioni... }
for(int i=0;i < n;i++){ istruzioni } while ( i < 5) { i=a.doSomething(); } do { i=a.doSomething(); } while ( i < 5)
switch( i ){ case 1: b.func(); case 2: a.func(); default: c:func(); }
while ( i < 5) { i=a.doSomething(); if(i<0) break; } jmp0: while (b.func()) { if (a.func()) continue jmp0; else continue jmp1; } jmp1:
Come tutti gli oggetti essi sono:
I vettori possono essere dichiarati in 2 modi
int iArray [];
int [] iArray;
E' possibile inizializzare vettori di dati primitivi con
int [] iArray = { 1, 3 , 5, 6};
iArray.length => numero degli elementi del vettore.
La lunghezza di un vettore, una volta creato, non puo' essere piu' cambiata. Se invece avete bisogno di un vettore che possa crescere o decrescere a piacere,bisogna usare l'oggetto ArrayList
In Java un vettore bidimensionale(o in generale multidimensionale) viene definito come un vettore di vettori:
int iArray[][] = new int[2][5] ;
ma potete avere anche righe di lunghezza differente:
int jArray[][] = { {1, 3, 4},{2,4},{5}};
jArray.length => 3
jArray[0].length => 3
jArray[1].length => 2
jArray[2].length => 1
Le stringhe possono essere inizializzate nella dichiarazione :
String str= new String("A string");
String str1= " and another string"
L'unico caso in Java di "sovraccarico(overload)" di un operatore (+):
String str2 = str + str1;
Allora str2 conterra':
"A string and another string";
Confronto tra stringhe
if(str1.equals(str2))
Lunghezza di una stringa
str1.length()
Sottostringa a partire da i di lunghezza k
str1.substring(i,k)
Posizione di una sottostringa str2
str1.indexOf(str2)
Un oggetto molto utile per trattare stringhe di qualsiasi lunghezza e' l'oggetto StringBuffer